1.Spring

1.1简介

  • Spring:春天----->给软件行业带来了春天!

  • 2002,首次推出了Spring框架的雏形:interface21框架!

  • Spring框架即以inteface21框架为基础,经过重新设计,并不断丰富其内涵,于2004年3月24日,发布了1.0正式版。

  • Rod Johnson,SpringFramework创始人,著名作者,很难想象Rod Johnson的学历,真的让人大吃一惊,他是悉尼大学博士,然而他的专业却不是计算机,而是音乐家

  • spring理念:使现有的技术更加容易使用,本身是一个大杂烩,整合了现有的技术框架!

  • SSH :Struct2 + Spring + Hibernate

  • SSM:SpringMvc + Spring + Mybatis

官网:https://spring.io/projects/spring-framework#overview

官方下载地址https://repo.spring.io/ui/native/release/org/springframework/spring

GitHub:https://github.com/spring-projects/spring-framework

Maven:如果我们只导入spring的包有很多需要一个一个导入,我们可以导入更庞大的mvc的包,里面包含了spring

<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.2.0.RELEASE</version>
</dependency>

1.2优点

  • Spring是一个开源的免费的框架(容器)
  • Spring是一个轻量级的,非入侵式的框架!
  • 控制反转(IOC),面向切面编程(APO)
  • 支持事务的处理,对框架整合的支持!

总结一句话:Spring就是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架!

1.3组成

七大模块组成

1.4扩展

在Spring的官网有这个介绍:现代化的Java开发!说白就是基于Spring的开发!

  • SpringBoot

    • 一个快速开发的脚手架
    • 基于SpringBoot可以快速的开发单个微服务
    • 预定大于配置
  • SpringCloud

    • SpringCloud是基于SpringBoot实现的

因为现在大多数公司都在使用SpringBoot进行快速开发,学会SpringBoot的前提,需要完全掌握Spring及SpringMVC!承上启下的作用!

弊端:发展了太久之后,违背了原来的理念!配置十分繁琐,人称配置地狱!

2.IOC理论推导

原来的架构

  1. UserDao 接口
  2. UserDaolmpl 实现类
  3. UserService 业务接口
  4. UserServiceImpl 业务实现类

在我们之前的业务中,用户的需求可能会影响我们原来的代码,我们需要根据用户的需求去修改源代码!如果程序代码量十分大,修改一次的成本十分昂贵!

我们使用一个set接口实现,已经发生了革命性的变化

private UserDao userDao;public void setUserDao(UserDao userDao) {this.userDao = userDao;
}
  • 之前,程序是主动创建对象!控制权在程序员手上
  • 使用了set注入后,程序不再具有主动性,而是变成了被动的接收对象!

这种思想,从本质上解决了问题,我们程序员不用去管理对象的创建了,系统的耦合性大大降低,可以更加专注的在业务的实现上,这就是IOC的原型

在我们原来写的代码,每个模块都相互依赖,一个模块出错,全部都运行不了

我们使用IOC容器后的代码,由我们ICO来管理这些模块

未来的代码,每个模块都单独运行,互不影响

IOC本质

**控制反转Ioc,是一种设计思想,DI(依赖注入)是实现IOC的一种方法,**也有人认为DI只是Ioc的另一种说法。没有Ioc的程序中,我们使用面向对象编程,对象的创建与对象间的依赖关系完全写死在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就说:获得依赖对象的方式反转了。

采用xml方式配置Bean的时候,Bean的定义信息和实现分离的,而采用注解的方式可以吧两者合为一体,Bean的定义信息直接以注解的新式定义在实现类中,从而达到了零配置的目的(自动装配)。

控制反转是一种通过描述(XML或注解)并通过第三方去生成或获取特定对象的方式,在Spring中实现控制反转的是Ioc容器,其实现方式是依赖注入(DI)

3.HelloSpring

给对象赋值

pojo

package com.xh.pojo;public class Hello {private String hello;public String getHello() {return hello;}public void setHello(String hello) {this.hello = hello;}@Overridepublic String toString() {return "Hello{" +"hello='" + hello + '\'' +'}';}
}

beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><!--    使用Spring来创建对象,在Spring中这些都称为Bean类型 变量名 = new 类型();Hello hello = new Hello();id=变量名class=new 的新对象property 相当于给对象中的属性设置一个值!
--><bean id="Hello" class="com.xh.pojo.Hello"><property name="hello" value="Spring"/></bean>
</beans>

测试

@Test
public void test1(){ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");Hello hello = (Hello) context.getBean("Hello");System.out.println(hello.toString());
}

赋值对象

这里指的是,我们通过xml的方式,给serviceImpl中的set方法注入dao的对象

dao

public interface UserDao {void getuser();
}

dao实现类

package com.xc.dao;public class MysqlDaoImpl implements UserDao{public void getuser() {System.out.println("Mysql");}
}
package com.xc.dao;public class OracleImpl implements UserDao{public void getuser() {System.out.println("oracle");}
}

service

package com.xc.service;public interface UserService {void getuser();
}

service实现类

package com.xc.service;import com.xc.dao.UserDao;public class UserServiceImpl implements UserService{private UserDao userDao;public void setUserDao(UserDao userDao) {this.userDao = userDao;}public void getuser() {userDao.getuser();}
}

beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd">
<!--    必须要实现set方法,底层就是调用的set方法--><bean id="mysqlimpl" class="com.xc.dao.MysqlDaoImpl"/><bean id="oracleimpl" class="com.xc.dao.OracleImpl"/><bean id="userservice" class="com.xc.service.UserServiceImpl">
<!--        ref:引用上面spring已经创建好的对象value:写入基本的数据类型
--><property name="userDao" ref="oracleimpl"/></bean></beans>

测试

@Test
public void test1(){ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");UserService userservice = (UserService) context.getBean("userservice");userservice.getuser();
}

4.IOC创建对象的方式

使用IOC创建对象的时候一定要定义构造器

通过IOC创建对象流程:

我们在new ClassPathXmlApplicatonContext(beans.xml)

的时候通过无参构造已经将我们配置文件中的bean创建到容器中(new 对象)实例化了

通过有参构造创建对象

<!--    方式一    通过无参构造创建对象-->
<bean id="user" class="com.kuang.pojo.User"></bean><!--    方式二,通过有参构造参数下标来赋值--><bean id="user" class="com.kuang.pojo.User"><constructor-arg index="0" value="杨贵强"/></bean><!--    方式三,通过有参构造参数类型创建对象--><bean id="user" class="com.kuang.pojo.User"><constructor-arg type="java.lang.String" value="云朵"/></bean><!--    方式四,通过有参构造参数顺序创建对象--><bean id="user" class="com.kuang.pojo.User"><constructor-arg value="星辰"/></bean>

一共有四中方法通过IOC创建对象

总结

在配置文件加载的时候,容器中管理的对象就已经初始化了(new 对象)!

5.Spring配置

别名

<!--    别名-->
<!--    我们可以给我们bean起一个别名,name对应我们需要起别名的id,alias对应我们别名名称-->
<!--    别名就是小名,我们在getbean的时候用大名还是小名都可以获取到对象--><alias name="user" alias="user2"/>

Bean的配置

<!--id:bean的唯一标识符,也就是这个对象的名称class:bean对象所对应的全限定名:包名+类型name:也是别名,而且name可以同时取多个别名
--><bean id="user" class="com.kuang.pojo.User" name="user2 user3,user4"><property name="name" value="星辰"/></bean>

import

一般用于团队开发使用,它可以将多个配置文件,导入合并为一个

假设,现在项目中有多个人开发,这三个人复制不同的类开发,不同的类需要注册在不同的bean中,我们可以利用import将所有人的beans.xml合并为一个总的!

  • 张三
  • 李四
  • 王五
  • applicationcontext.xml
<import resource="beans.xml"/>
<import resource="beans1.xml"/>
<import resource="beans2.xml"/>

使用的时候,直接使用总的配置就可以了

6.DI依赖注入

1.构造器注入

详情看4.IOC创建对象方式

2.Set方式注入【重点】

  • 依赖注入:Set注入

    • 依赖:bean对象创建依赖容器
    • 注入:bean对象中的所有属性,由容器注入!

【环境搭建】

  1. 复杂类型

    package com.kuang.pojo;public class Address {private String address;public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}
    }
    
  2. 证实测试对象

package com.kuang.pojo;import java.util.*;public class Student {private String name;private Address address;private String[] books;private List<String> hobbys;private Map<String,String> car;private Set<String> games;private String wife;private Properties info;public String getName() {return name;}public void setName(String name) {this.name = name;}public Address getAddress() {return address;}public void setAddress(Address address) {this.address = address;}public String[] getBooks() {return books;}public void setBooks(String[] books) {this.books = books;}public List<String> getHobbys() {return hobbys;}public void setHobbys(List<String> hobbys) {this.hobbys = hobbys;}public Map<String, String> getCar() {return car;}public void setCar(Map<String, String> car) {this.car = car;}public Set<String> getGames() {return games;}public void setGames(Set<String> games) {this.games = games;}public String getWife() {return wife;}public void setWife(String wife) {this.wife = wife;}public Properties getInfo() {return info;}public void setInfo(Properties info) {this.info = info;}@Overridepublic java.lang.String toString() {return "Student{" +"name=" + name +", address=" + address +", books=" + Arrays.toString(books) +", hobbys=" + hobbys +", car=" + car +", games=" + games +", wife=" + wife +", info=" + info +'}';}
}

ApplicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="address" class="com.kuang.pojo.Address"><property name="address" value="湖北省武汉市"/></bean><!--    第一种普通值注入--><bean id="student" class="com.kuang.pojo.Student">
<!--        普通set属性进行赋值--><property name="name" value="星辰"/>
<!--        引用类型注入--><property name="address" ref="address"/>
<!--        数组--><property name="books"><array><value>语文</value><value>数学</value><value>英语</value></array></property><!--        list集合--><property name="hobbys"><list><value>苹果</value><value>香蕉</value><value>西瓜</value></list></property>
<!--        map集合--><property name="car"><map><entry key="ID" value="10000"/><entry key="age" value="18"/></map></property>
<!--        set集合--><property name="games"><set><value>湖北</value><value>北京</value><value>上海</value></set></property>
<!--        properties集合--><property name="info"><props><prop key="湖北">武汉</prop><prop key="山东">菏泽</prop><prop key="河南">郑州</prop></props></property>
<!--        注入null--><property name="wife"><null></null></property></bean></beans>

测试

import com.kuang.pojo.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class Test {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");Student student = (Student) context.getBean("student");System.out.println(student.getName());}
}

3.拓展方式注入

C命名空间注入和B命名空间注入

P命名空间注入

<bean id="user" class="com.kuang.pojo.User" p:name="星辰" p:age="18"/><!--这里等价于下面注入,只是更简便了--><bean id="user" class="com.kuang.pojo.User"><property name="name" value="星辰"/><property name="age" value="18"/>
</bean>

C命名空间注入

<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:p="http://www.springframework.org/schema/p"xmlns:c="http://www.springframework.org/schema/c"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><!--    c命名空间,是通过构造器注入 constructor-arg--><bean id="user" class="com.kuang.pojo.User" c:age="18" c:name="xc"/>
</beans>

注意点

7.Bean的作用域

  • 单例模式(singleton)容器里面只存在一个相同的对象,用户多次new这个对象,都是拿的容器中同一个

    <bean id="user" class="com.kuang.pojo.User" c:age="18" c:name="xc" scope="singleton"/>
    

  • 原型模式(prototype)用户new多少个对象,就创建多少个对象

    <bean id="user" class="com.kuang.pojo.User" c:age="18" c:name="xc" scope="prototype"/>
    

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c2Z3OGk9-1659404482191)(http://img.jyxcwl.cn/image-20220301091100529.png)]

7.Bean自动装配

  • 自动装配式Spring满足bean依赖一种方式
  • Spring会在上下文自动寻找,并自动给bean装配属性!

在Spring中有三种装配的方式

  • 在xml中显示的配置
  • 在java中显示配置
  • 隐式的自动自动装配bean【重要】

测试

  1. 环境搭建
  • 一个人有两个宠物!
package com.kuang.pojo;public class Cat {public void shot(){System.out.println("miao~");}
}
package com.kuang.pojo;public class Dog {public void shot(){System.out.println("wang~");}
}
package com.kuang.pojo;public class person {private Cat cat;private Dog dog;private String name;@Overridepublic String toString() {return "person{" +"cat=" + cat +", dog=" + dog +", name='" + name + '\'' +'}';}public Cat getCat() {return cat;}public void setCat(Cat cat) {this.cat = cat;}public Dog getDog() {return dog;}public void setDog(Dog dog) {this.dog = dog;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="cat" class="com.kuang.pojo.Cat"/><bean id="dog" class="com.kuang.pojo.Dog"/><bean id="person" class="com.kuang.pojo.person"><property name="cat" ref="cat"/><property name="dog" ref="dog"/><property name="name" value="星辰"/></bean></beans>
import com.kuang.pojo.person;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class test {@Testpublic void test1(){ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");person person = (com.kuang.pojo.person) context.getBean("person");//cat对象.方法person.getCat().shot();}
}
miao~

自动装配(Autowire)

上面那些通过propert方式使用ref指定一个引用对象,很麻烦,所以就有了自动装配,bean自动帮我们设置ref中的引用对象

方式一

使用byname

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="cat" class="com.kuang.pojo.Cat"/><bean id="dog" class="com.kuang.pojo.Dog"/><bean id="person" class="com.kuang.pojo.person" autowire="byName"><property name="name" value="星辰"/></bean></beans>
  1. 这里使用byname表示,
  2. 这里需要绑定的bean id 必须唯一

方式二

使用bytype

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="cat" class="com.kuang.pojo.Cat"/><bean id="dog" class="com.kuang.pojo.Dog"/><bean id="person" class="com.kuang.pojo.person" autowire="byType"><property name="name" value="星辰"/></bean></beans>
  1. 这里bytype表示,绑定的是class类型,这里bean的id可以不要,但是class必须要唯一

总结

  • byname的时候,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致!
  • bytype的时候,需要保证所有bean的class唯一,并且这个bean需要和自动注入的属性的类型一致!

注解自动装配

@Autowired

他的功能跟我们autowire="bytype"执行的效果是一样的,

先更具byname来设置,如果byname找不到,那么就bytype寻找class

以前我们使用自动装配

现在注解装配,更简洁

@Resource

也是一个自动装配的注解

小结

@Resource和@Autowired区别:

  • 都是用来自动装配的,都可以放在属性字段上
  • @Autowired通过byType的方式实现,而且必须要求这个对象存在!【常用】
  • @Resource默认通过byname的方式实现,如果找不到名字,则通过bytype实现!如果两个都找不到的情况下,就会报错!【常用】
  • 两个注解执行顺序不同:@AutoWired通过bytype的方式实现,@Resource默认通过byname的方式实现。

8.spring使用注解开发

在Spring4之后,需使用注解开发,必须要保证aop的包导入了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KXAts48z-1659404482196)(C:\Users\杨贵强\AppData\Roaming\Typora\typora-user-images\image-20220301111000405.png)]

在使用注解需要导入 context约束,增加注解支持

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsd"><!--    开启注解支持--><context:annotation-config/>
<!--    开启扫描包,这样使用注解的时候,才可以扫描包下的bean--><context:component-scan base-package="com.kuang.dao"/>
</beans>

bean注解注入容器

pojo

package com.kuang.dao;import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;@Component //等价于 //    <bean id="user" class="com.kuang.dao.User"/>
public class User {private String name="星辰";
}

test

import com.kuang.dao.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class test {@Testpublic void test1(){ApplicationContext Context = new ClassPathXmlApplicationContext("applicationcontext.xml");User user = (User) Context.getBean("user");System.out.println(user.getName());}
}

对象属性如何注入

package com.kuang.dao;import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;@Component //等价于 //    <bean id="user" class="com.kuang.dao.User"/>
public class User {@Value("星辰")  // 等价于 <property name="name" value="星辰"/>private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}
}
import com.kuang.dao.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class test {@Testpublic void test1(){ApplicationContext Context = new ClassPathXmlApplicationContext("applicationcontext.xml");User user = (User) Context.getBean("user");System.out.println(user.getName());}
}

衍生注解

@Component有几个衍生注解,我们在web开发中,会按照mvc三层架构分层!

  • dao 【@Repository】
  • service 【@service】
  • controller 【@controller】

这四个注解功能都是一样的,都是代表将某个类注册到spring中,装配Bean

自动装配配置

@Autowired:自动装配通过类型然后名称如果Autowired不能唯一自动装配上属性,则需要通过@Qualifier(value="xxx")
@Nullable  :字段标记了这个注解,说明这个字段可以为null
@Resource  :自动装配通过名称然后类型 【跟Autowired顺序相反】

作用域

package com.kuang.dao;import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;@Component //等价于 //    <bean id="user" class="com.kuang.dao.User"/>
@Scope("prototype") //单例singleton,原型prototype
public class User {private String name="星辰";public String getName() {return name;}public void setName(String name) {this.name = name;}
}

小结

xml与注解:

  • xml更加万能,适用于任何场合!维护简单方便
  • 注解不是自己类使用不了,维护相对复杂

xml与注解最佳实践:

  • xml用来管理bean;
  • 注解只负责完成属性的注入@value
  • 我们在使用的过程中,只需要注意一个问题:必须让注解生效,就需要开启注解的支持和包扫描
<!--    开启注解支持--><context:annotation-config/>
<!--    开启扫描包,这样使用注解的时候,才可以扫描包下的bean--><context:component-scan base-package="com.kuang.dao"/>

9.使用java的方式配置Spring

我们现在要完全不使用spring的xml配置了,全部交给java来做

JavaConfig是spring的一个子项目,在spring4之后,成为了一个核心功能

pojo

package com.kuang.pojo;import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;@Component   //等价于 <bean id="user" class="com.kuang.pojo.user" />
public class User {@Value("星辰")private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}
}

configuration

package com.kuang.config;import com.kuang.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;//这个也会spring容器托管,注册到容器中,因为他本来就是一个@Coponent
//@Config代表这是一个配置类,就和我们之前看的beans.xml
@Configuration
public class Config1 {//注册一个bean,就相当于我们之前写的一个bean标签//这个方法的名字,就相当于bean标签中的id属性//这个方法的返回值,就相当于bean标签中的class属性@Beanpublic User getuser(){return new User();//就说返回要注入到bean的对象}/*<bean id="user" class="com.kuang.pojo.user"><property name="name" value="星辰"/></bean><bean id=getuser class="com.kuang.dao.User"><property name="getuser" ref="user"/></bean>*/ }

测试

import com.kuang.config.Config1;
import com.kuang.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class Test {@org.junit.Testpublic void test1(){ApplicationContext context = new AnnotationConfigApplicationContext(Config1.class);User getuser = (User) context.getBean("getuser");System.out.println(getuser.getName());}
}

这种纯java的配置方式,在springboot中随处可见

10.AOP

静态代理

租房流程

好处:

  1. 可以使真实角色操作更加纯粹,不用去关注一些公共的业务
  2. 公共也就交给代理角色!实现了业务的分工
  3. 公共业务发送扩展的时候,方便集中管理!

缺点:

  • 一个真实角色就会产生一个代理角色,代码量会翻倍开发效率就会变低

角色分析

  • 抽象角色:一般会使用接口或者抽象类来解决
  • 真实角色:被代理的角色
  • 代理角色:代理真实角色,代理真实角色后,我们一般会做一些附属操作【例如在原有的方法上,增加日志】
  • 客户:访问代理对象的人!

没有引入代理

引入代理

抽象角色:房子

package com.kuang.jingtai;public interface zhufang {//共同租房的形式void zhufang();
}

房东

package com.kuang.jingtai;public class fangdong implements zhufang{//房东实现租房的接口public void zhufang() {System.out.println("成功租到房子");}
}

代理

package com.kuang.jingtai;public class daili implements zhufang{private fangdong fangdong;public daili() {}public daili(com.kuang.jingtai.fangdong fangdong) {this.fangdong = fangdong;}//找中介租房的时候,public void zhufang() {//代理可以做一些附加的格外事情,//交钱jiaoqian();//签合同hetong();//用户交完钱后和签完合同后,直接吧房东的房子给用户fangdong.zhufang();}public void jiaoqian(){System.out.println("交钱");}public void hetong(){System.out.println("签合同");}}

package com.kuang.jingtai;public class wo {public static void main(String[] args) {//获取我们想租房的房东fangdong fangdong = new fangdong();//获取我们的中介daili daili = new daili(fangdong);//通过代理进行租房daili.zhufang();}
}

加深理解

我们想在原因的代码功能基础上增加日志功能!

package com.kuang.demo1;//业务接口
public interface service {void add();void delete();void update();void query();
}
package com.kuang.demo1;//业务实现类
public class serviceImpl implements service{public void add() {System.out.println("新增一个用户");}public void delete() {System.out.println("清除一个用户");}public void update() {System.out.println("修改一个用户");}public void query() {System.out.println("查询一个用户");}
}
package com.kuang.demo1;//代理类
public class dailiImpl implements service{private serviceImpl serviceimpl;public void setServiceimpl(serviceImpl serviceimpl) {this.serviceimpl = serviceimpl;}//我们可以代理业务实现,增加日志功能public void add() {log("add");serviceimpl.add();}public void delete() {log("delete");serviceimpl.delete();}public void update() {log("update");serviceimpl.update();}public void query() {log("query");serviceimpl.query();}public void log(String msg){System.out.println("执行了"+msg+"方法");}
}
package com.kuang.demo1;public class test {public static void main(String[] args) {//真实对象serviceImpl service = new serviceImpl();//代理对象dailiImpl daili = new dailiImpl();//通过set方法代理我们真实对象daili.setServiceimpl(service);//通过代理调用方法daili.query();}
}

动态代理

package com.kuang.dongtai;public interface Host {void zhufang();
}
package com.kuang.dongtai;public class fangdong implements Host{public void zhufang() {System.out.println("成功出租房子");}
}
package com.kuang.dongtai;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class invocationHandler implements InvocationHandler {//需要被代理的接口private Host host;public void setHost(Host host) {this.host = host;}//程序自动生成代理类public Object getProxy(){return Proxy.newProxyInstance(this.getClass().getClassLoader(), host.getClass().getInterfaces(),this);}//处理代理实例,并返回结果public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//动态的本质就是通过反射机制实现的Object invoke = method.invoke(host, args);return invoke;}
}
package com.kuang.dongtai;public class test {public static void main(String[] args) {fangdong fangdong = new fangdong();invocationHandler invocationHandler = new invocationHandler();invocationHandler.setHost(fangdong);fangdong proxy =(fangdong)invocationHandler.getProxy();proxy.zhufang();}
}

实现AOP日志

AOP底层是基于动态代理实现的,动态代理的是接口

<!--        导入aop依赖--><!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver --><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.4</version></dependency>

方式一

使用Spring自带的API接口实现

接口

package com.kuang.service;public interface UserService {void add();void delete();void update();void select();
}

实现类

package com.kuang.service;public class UserServiceImpl implements UserService{public void add() {System.out.println("增加了一个用户");}public void delete() {System.out.println("清除了一个用户");}public void update() {System.out.println("修改了一个用户");}public void select() {System.out.println("查询了一个用户");}
}

日志

前置

package com.kuang.aop;import org.springframework.aop.BeforeAdvice;
import org.springframework.aop.MethodBeforeAdvice;import java.lang.reflect.Method;public class BeforeLog implements MethodBeforeAdvice {//前置增强//method:方法//objects:参数//o:目标对象public void before(Method method, Object[] objects, Object o) throws Throwable {System.out.println(o.getClass().getName()+"执行了"+method.getName()+"方法");}
}

后置

package com.kuang.aop;import org.springframework.aop.AfterReturningAdvice;import java.lang.reflect.Method;public class AfterAdviceLog implements AfterReturningAdvice {//后置增强//o:返回值//method:方法//objects:参数//o1:目标对象public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {System.out.println(method.getName()+"执行完毕"+"返回值"+o);}
}

配置类

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttps://www.springframework.org/schema/aop/spring-aop.xsd
"><!--先将我们对象全部注入到spring容器中--><bean id="UserServiceImpl" class="com.kuang.service.UserServiceImpl"/><bean id="AfterAdviceLog" class="com.kuang.aop.AfterAdviceLog"/><bean id="BeforeLog" class="com.kuang.aop.BeforeLog"/><!--    使用aop:config 来给配置切入点日志--><aop:config>
<!--        切入点,id=切入名称,expression:表达式= execution(修饰符 包名.类名.所以方法(所有参数)) --><aop:pointcut id="service" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/><!--        通知:前置增强和后置增强,advice-ref:日志类   pointcut-ref:切入点--><aop:advisor advice-ref="BeforeLog" pointcut-ref="service"/><aop:advisor advice-ref="AfterAdviceLog" pointcut-ref="service"/></aop:config></beans>

execution表达式

方式二

自定义切面类,给写入点通知

自定义切面

package com.kuang.utils;public class log {public void Before(){System.out.println("执行方法前");}public void after(){System.out.println("执行方法后");}
}

自定义切面

    <aop:config>
<!--        自定义切面,ref 要引用的类,就说我们自定义的切面类的bean id--><aop:aspect ref="diylog">
<!--            定义切入点--><aop:pointcut id="log" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/>
<!--            通知,前置和后置增强--><aop:before method="Before" pointcut-ref="log"/><aop:after method="after" pointcut-ref="log"/></aop:aspect></aop:config>

总结:

方式一:使用spring的API接口【主要SpringAPI接口实现】

方式二:自定义实现AOP【主要是切面定义】

使用注解实现

package com.kuang.utils;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;//使用注解配置AOP@Aspect//标志这是一个切面
public class anocation {//    前置增强@Before("execution(* com.kuang.service.UserServiceImpl.*(..))")public void Before(){System.out.println("方法执行前");}
//    后置增强@After("execution(* com.kuang.service.UserServiceImpl.*(..))")public void After(){System.out.println("方法执行后");}//环绕增强@Around("execution(* com.kuang.service.UserServiceImpl.*(..))")public void around(ProceedingJoinPoint point) throws Throwable {System.out.println("===环绕前===");Object proceed = point.proceed();//执行原本业务方法System.out.println("===环绕后===");}}

applicationcontext.xml

<!--开启aop注解支持--><aop:aspectj-autoproxy/>

结果

===环绕前===
方法执行前
增加了一个用户
===环绕后===
方法执行后

11.整合Mybatis

步骤:

  1. 导入相关依赖包
  • junt
  • springmvc
  • aspectjweaver
  • mysql
  • mybatis
  • spring-jdbc
  • mybatis-spring
  • lombok
  1. 编写xml配置文件

    • db.properties【数据库信息】
    • mybatis-config.xml【mybatis配置】
    • applicationcontext.xml【Spring配置】
  2. 测试

回忆Mybatis

pojo

package com.kuang.pojo;import lombok.Data;@Data
public class user {private int id;private String name;private String password;
}

mapper

package com.kuang.dao;import com.kuang.pojo.user;import java.util.List;public interface UserMapper {List<user> queryUserList();
}

mybatis工具类

package com.kuang.utils;import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;import java.io.InputStream;public class MybatisUtils {private static SqlSessionFactory sqlSessionFactory;static {try {String resource = "mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);sqlSessionFactory= new SqlSessionFactoryBuilder().build(inputStream);}catch (Exception e){e.toString();}}public static SqlSession getSqlSession(){return sqlSessionFactory.openSession();}
}

数据库信息

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis
username=root
password=0000

mybatis配置信息

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--    导入数据库--><properties resource="db.properties"/><!--    开启别名--><typeAliases><package name="com.kuang.pojo.user"/></typeAliases><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="${driver}"/><property name="url" value="${url}"/><property name="username" value="${username}"/><property name="password" value="${password}"/></dataSource></environment></environments><!--    注册mapper--><mappers><mapper resource="com/kuang/dao/UserMapper.xml"/></mappers></configuration>

test

import com.kuang.dao.UserMapper;
import com.kuang.pojo.user;
import com.kuang.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;import java.util.List;public class Test {@org.junit.Testpublic void test1(){SqlSession sqlSession = MybatisUtils.getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);List<user> users = mapper.queryUserList();for (user user : users) {System.out.println(user);}sqlSession.close();}
}

整合方式一

pojo

package com.kuang.pojo;import lombok.Data;@Data
public class user {private int id;private String name;private String password;
}

UserMapper

package com.kuang.dao;import com.kuang.pojo.user;import java.util.List;public interface UserMapper {List<user> queryUserList();
}

UsermapperImpl

package com.kuang.dao;import com.kuang.pojo.user;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;import java.util.List;public class UserMapperImpl implements UserMapper{//    构造SqlSessionprivate SqlSessionTemplate sqlSession;
//这里spring中的bean通过set方法进行注入public void setSqlSession(SqlSessionTemplate sqlSession) {this.sqlSession = sqlSession;}public List<user> queryUserList() {UserMapper mapper = sqlSession.getMapper(UserMapper.class);return mapper.queryUserList();}
}

Usermapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.kuang.dao.UserMapper"><!--  数据库字段别名  --><resultMap id="queryUserList_Map" type="com.kuang.pojo.user"><result property="password" column="pwd"/></resultMap><select id="queryUserList" resultMap="queryUserList_Map" parameterType="com.kuang.pojo.user">select * from user</select>
</mapper>

mybatis配置

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><!--    开启别名--><typeAliases><package name="com.kuang.pojo.user"/></typeAliases><!--    开启日志-->
<!--    <settings>-->
<!--        <setting name="" value=""/>-->
<!--    </settings>--><!--    注册mapper--><mappers><mapper resource="com/kuang/dao/UserMapper.xml"/></mappers></configuration>

ApplicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><!--    这里使用Spring自带的jdbc数据源--><bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"><property name="driverClassName" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/mybatis"/><property name="username" value="root"/><property name="password" value="0000"/></bean><!--    构造SqlSessionFactory--><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="datasource"/>
<!--        引入mybtais整合--><property name="configLocation" value="classpath:mybatis-config.xml"/></bean><!--    通过构造器获取SqlSession--><bean id="SqlSession" class="org.mybatis.spring.SqlSessionTemplate"><constructor-arg index="0" ref="sqlSessionFactory"/></bean><!--    添加bean--><bean id="UserMapperImpl" class="com.kuang.dao.UserMapperImpl"><property name="sqlSession" ref="SqlSession"/></bean></beans>

测试

import com.kuang.dao.UserMapper;
import com.kuang.pojo.user;
import com.kuang.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;import java.util.List;public class Test {@org.junit.Testpublic void test1(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("ApplicationContext.xml");UserMapper userMapperImpl = (UserMapper) applicationContext.getBean("UserMapperImpl");List<user> users = userMapperImpl.queryUserList();for (user user : users) {System.out.println(user);}}
}

方式二

SqlSessionDaoSupport

package com.kuang.dao;import com.kuang.pojo.user;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.support.SqlSessionDaoSupport;import java.util.List;//通过基础SqlSessionDaoSupport简化代码,不用手动set方法去设置sqlSession
public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper{public List<user> queryUserList() {SqlSession sqlSession = getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);return mapper.queryUserList();//        return getSqlSession().getMapper(UserMapper.class).queryUserList();}
}
<!--    使用SqlSessionDaoSupport实现spring整合操作mybatis--><bean id="UserMapperImpl2" class="com.kuang.dao.UserMapperImpl2"><property name="sqlSessionFactory" ref="sqlSessionFactory"/></bean>

12.声明式事务

在不改变原有的代码,实现解耦,配置事务

spring中不允许手动回滚,需要配置事务的bean进行自动事务

回顾事务

  • 要么都成功,要么都失败!
  • 事务在项目开发中,十分的重要,涉及到数据的一致性问题,不能马虎
  • 确保完整性和一致性

事务的ACID原则

  • 原子性
  • 一致性
  • 隔离性
    • 多个业务可能操作同一个资源,防止数据瞬坏
  • 持久性
    • 事务一旦提交,无论系统发生什么问题,结果都不会被影响,被持久化写到数据库中

Spring中的事务管理

pojo

package com.kuang.pojo;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {private int id;private String name;private String password;
}

dao

package com.kuang.dao;import com.kuang.pojo.User;import java.util.List;public interface UserMapper {List<User> queryUserList();int addUser(User user);int deleteUser(int id);
}

impl

package com.kuang.dao;import com.kuang.pojo.User;
import org.mybatis.spring.SqlSessionTemplate;import java.util.List;public class UserMapperImpl implements UserMapper{private SqlSessionTemplate SqlSession;public void setSqlSession(SqlSessionTemplate sqlSession) {SqlSession = sqlSession;}public List<User> queryUserList() {UserMapper mapper = SqlSession.getMapper(UserMapper.class);try {mapper.addUser(new User(6,"xc","123456"));mapper.deleteUser(5);SqlSession.commit();}catch (Exception e){SqlSession.rollback();}return mapper.queryUserList();}public int addUser(User user) {return 0;}public int deleteUser(int id) {return 0;}
}

mapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.kuang.dao.UserMapper"><resultMap id="queryUserList_Map1" type="com.kuang.pojo.User"><result property="password" column="pwd"/></resultMap><select id="queryUserList" resultMap="queryUserList_Map1" parameterType="com.kuang.pojo.User">select * from user</select><insert id="addUser" parameterType="com.kuang.pojo.User">insert into user set id=#{id},name=#{name},pwd=#{password}</insert><!--    这里故意写错,执行事务--><delete id="deleteUser" parameterType="com.kuang.pojo.User">delet user where id=#{id}</delete></mapper>

mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><mappers><mapper resource="com/kuang/dao/UserMapper.xml"/></mappers>
</configuration>

applicationcontext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:tx="http://www.springframework.org/schema/tx"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/txhttps://www.springframework.org/schema/tx/spring-tx.xsdhttp://www.springframework.org/schema/aophttps://www.springframework.org/schema/aop/spring-aop.xsd
"><bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"><property name="driverClassName" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/mybatis"/><property name="username" value="root"/><property name="password" value="0000"/></bean><!-- 构建SqlSessionFactory --><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="dataSource" /><property name="configLocation" value="classpath:mybatis-config.xml"/></bean><!-- 通过构造器创建sqlsession --><bean id="SqlSession" class="org.mybatis.spring.SqlSessionTemplate"><constructor-arg index="0" ref="sqlSessionFactory"/></bean><!--注册bean--><bean id="UserMapperImpl" class="com.kuang.dao.UserMapperImpl"><property name="sqlSession" ref="SqlSession"/></bean><!--    通过构造器创建声明式事务对象--><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><constructor-arg index="0" ref="dataSource"/></bean><!--    结合AOP实现事务的织入-->
<!--    配置事务通知:--><tx:advice id="tx" transaction-manager="transactionManager">
<!--        给那些方法配置事务-->
<!--        配置事务的传播特性:propagation=***--><tx:attributes><!--标记那些方法开启配置事务--><tx:method name="add" propagation="REQUIRED"/><tx:method name="update" propagation="REQUIRED"/><tx:method name="delete" propagation="REQUIRED"/>
<!--            read-only 只读--><tx:method name="query" read-only="true"/></tx:attributes></tx:advice><!--    配置事务切面--><aop:config><!--切入点--><aop:pointcut id="txpointcut" expression="execution(* com.kuang.dao.*.*(..))"/><!--通知--><aop:advisor advice-ref="tx" pointcut-ref="txpointcut"/></aop:config></beans>

test

import com.kuang.dao.UserMapper;
import com.kuang.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;import java.util.List;public class test {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");UserMapper userMapperImpl = (UserMapper) context.getBean("UserMapperImpl");List<User> users = userMapperImpl.queryUserList();for (User user : users) {System.out.println(user);}}
}

报错,但是spring通过aop切面执行了事务。数据库数据没有改变

思考

为什么需要事务?

  • 如果不配置事务,那可能数据提交不一致的问题;
  • 如果不在Spring中去配置声明式事务,我们就需要在代码中手动配置事务!
  • 事务在项目的开发中十分重要,涉及到数据的一致性和完整性问题,不容马虎!

Spring5,最全教程,带你认识IOC容器和AOP切面相关推荐

  1. 关于Spring中IOC容器和AOP协同工作的原理理解

    1.在详细介绍 IOC 容器的工作原理前,这里先介绍一下实现 IOC 所用到的一些辅助类,包括BeanDefinition.BeanReference.PropertyValues.PropertyV ...

  2. ASP.NET Core中使用IOC三部曲(一.使用ASP.NET Core自带的IOC容器)

    前言 本文主要是详解一下在ASP.NET Core中,自带的IOC容器相关的使用方式和注入类型的生命周期.这里就不详细的赘述IOC是什么 以及DI是什么了.. emm..不懂的可以自行百度. 正文 今 ...

  3. Spring IoC容器与Bean管理

    Spring IoC容器与Bean管理 一.Spring IoC容器与Bean管理 1.Spring快速入门 IoC控制反转 DI依赖注入 Spring概述 Spring IoC初体验 使用XML方式 ...

  4. Spring(一)--作用、IOC容器细节、搭配环境、Spring实验

    1.Spring作用:      1.生态体系庞大,全能型选手![springmvc是其一个子模块,jdbcTemplate能直接操作数据库!]      2.将其他组件粘合在一起      比如将S ...

  5. Spring IOC 容器启动、Bean生命周期详解

    前言 在Spring IOC 和 AOP 概览中,简要介绍了IOC容器和AOP,没有深入IOC容器Bean的实例化,此文承接上文深入分析Bean的实例化过程.生命周期. Spring IOC的过程 S ...

  6. Macbook自带软件删除最全教程

    Macbook自带软件删除最全教程 Mac中有很多平时用不到的软件比如(快播 TV.查找电话.照片.信息-),尤其是手机从iPhone阵营转HUAWEI阵营之后,太多的软件用不到了,但是每次打开Mac ...

  7. 001 spring5框架:java类工程,IOC:实体类表示表关系,AOP,JdbcTemplate模板,事务操作,Spring5 框架新功能:日志,为空注解,函数式风格,juint,Webflux

    1. Spring5 框架(Spring5 Framework)介绍 1.1 概念 1.Spring 是轻量级的开源的 JavaEE 框架 2.Spring 可以解决企业应用开发的复杂性 3.Spri ...

  8. Spring5 框架概述 、IOC 容器

    一.Spring5 框架概述 介绍 Spring 是轻量级的开源的 JavaEE 框架 Spring 可以解决企业应用开发的复杂性 Spring 有两个核心部分:IOC 和 Aop (1)IOC:控制 ...

  9. Docker最全教程——从理论到实战(六)

    Docker最全教程--从理论到实战(六) 原文:Docker最全教程--从理论到实战(六) 托管到腾讯云容器服务 托管到腾讯云容器服务,我们的公众号"magiccodes"已经发 ...

  10. Spring5 - 向IOC容器中添加组件的4种方式

    文章目录 概述 方式一: @CompentScan 适用场景 Code 方式二: @Bean 适用场景 Code 方式三: @Import 适用场景 Code Demo1 Code Demo2 + 实 ...

最新文章

  1. halcon 形状匹配
  2. 计算机网络应用和计算机应用有什么区别,什么是计算机网络技术?和计算机应用技术区别...
  3. VS Code 的常用快捷键和插件
  4. vb fso方式访问网络上的共享文件夹_经常遇见的网络故障详细分析及解决方法!...
  5. 为什么WebUI里新建任务的状态字段下拉框里没有released选项
  6. excel实战应用案例100讲(十三)-使用Python 对 Excel文件进行批量操作
  7. 地铁线路图的设计与实现
  8. PyTorch 1.0 中文官方教程:对抗性示例生成
  9. 【snmp】测试流程
  10. 苹果发布最新版本系统,弥补iOS 11耗电快等问题
  11. 应用程序窗口小部件App Widgets
  12. 简单典型二阶系统_非典型二阶系统的特性
  13. Ubuntu系统基本操作
  14. KMO检验和Bartlett球形检验
  15. 计算机芯片级维修包括哪些,计算机芯片级维修1
  16. float gpu 加速_(总结篇)使用 MATLAB GPU 加速计算|MATLAB 并行计算与分布式服务器|MATLAB技术论坛...
  17. 数据挖掘学习笔记3-贝叶斯与决策树
  18. Java分布式中文分词组件 - word分词(转自 https //github com/ysc/word)
  19. ImGui添加背景图片的两种方式
  20. php开源 tpshop,TPshop免费开源商城系统

热门文章

  1. #1024程序员节# cc2530 按键唤醒功耗模式PM3例程
  2. 理解SSD核心技术FTL
  3. ARM-linux开发板网线连接电脑访问外网
  4. KMS激活工具 HEU_KMS_Activator_CH_v7.8.4
  5. 使用vlmcsd搭建KMS服务器激活环境
  6. 如何使用 SEGGER Embedded Studio创建库文件?
  7. ACM 程序设计竞赛 数学题目
  8. 实现html文件和c# 交互
  9. 一种基于C6748 DSP+FPGA的软件无线电平台的设计及应用
  10. 它们把色情版 “微信” 的底裤都给挖出来了,网友: 草率了。。。