Spring5 1.、Spring 1.1、简介
Spring ——> 春天,为开源软件带来了春天
2002,首次推出了Spring框架的雏形:interface21框架!
Spring框架以interface21框架为基础,经过重新设计,并不断丰富其内涵,于2004年3月24日发布了1.0正式版
Spring的理念:使用现有的技术更加容易使用,本身是一个大杂烩,整合了现有的技术框架!
SSH:Struct2 + Spring + Hibernate(全自动持久化框架)!
SSM:SpringMVC + Spring + MyBatis(半自动持久化框架,可自定义性质更强)!
spring官网: https://spring.io/projects/spring-framework#overview
官方下载: https://repo.spring.io/release/org/springframework/spring/
GitHub: https://github.com/spring-projects/spring-framework
Spring Web MVC: spring-webmvc最新版
Spring Web MVC和Spring-JDBC的pom配置文件:
<dependency > <groupId > org.springframework</groupId > <artifactId > spring-webmvc</artifactId > <version > 5.2.7.RELEASE</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-jdbc</artifactId > <version > 5.2.7.RELEASE</version > </dependency >
1.2 优点
Spring是一个开源的免费的框架(容器)!
Spring是一个轻量级的、非入侵式的框架!
控制反转(IoC),面向切面编程(AOP)
支持事务的处理,对框架整合的支持!(几乎市面上所有热门框架都能整合进去)!
=== 总结一句话:Spring就是一个轻量级的控制反转(IoC)和面向切面编程(AOP)的框架! ===
1.3 组成
1.4、扩展 现代化的java开发 -> 基于Spring的开发!
Spring Boot
一个快速开发的脚手架
基于SpringBoot可以快速开发单个微服务
约定大于配置!
Spring Cloud
SpringCloud是基于SpringBoot实现的!
因为现在大多数公司都在使用SpringBoot进行快速开发,学习SpringBoot的前提,需要完全掌握Spring及SpringMVC!承上启下的作用!
2、IoC(控制反转)理论推导 传统 的调用
UserDao
package dao;public interface UserDao { void getUser () ; }
UserDaoImp
package dao;public class UserDaoImpl implements UserDao { public void getUser () { System.out.println("默认获取用户数据" ); } }
UserSevice
package Service;public interface UserService { void getUser () ; }
UserServiceImp
package Service;import dao.UserDao;import dao.UserDaoImpl;public class UserServiceImpl implements UserService { UserDao userDao = new UserDaoImpl(); public void getUser () { userDao.getUser(); } }
测试
package holle0;import Service.UserService;import Service.UserServiceImpl;public class MyTest0 { public static void main (String[] args) { UserService userService = new UserServiceImpl(); userService.getUser(); } }
在我们之前的业务中,用户的需求可能会影响我们原来的代码,我们需要根据用户的需求去修改原代码!如果程序代码量十分大,修改一次的成本代价十分昂贵!
改良: 我们使用一个Set接口实现。已经发生了革命性的变化!
private UserDao userDao;public void setUserDao (UserDao userDao) { this .userDao = userDao; }
set() 方法实际上是动态改变了 UserDao userDao 的 初始化部分(**new UserDaoImpl()**)
测试中加上
((UserServiceImpl)userService).setUserDao(new UserDaoImpl());
之前,程序是主动创建对象!控制权在程序猿手上 !
使用了set注入后,程序不再具有主动性,而是变成了被动的接受对象!(主动权在客户手上 )
本质上解决了问题,程序员不用再去管理对象的创建
系统的耦合性大大降低,可以更专注在业务的实现上
这是IoC(控制反转)的原型,反转(理解):主动权交给了用户
IoC本质
3、HolleSpring 在父模块中导入jar包
<dependency > <groupId > org.springframework</groupId > <artifactId > spring-webmvc</artifactId > <version > 5.2.7.RELEASE</version > </dependency >
pojo的Hello.java
package pojo;public class Hello { private String str; public String getStr () { return str; } public void setStr (String str) { this .str = str; } @Override public String toString () { return "Holle [str=" + str + "]" ; } }
在resource里面的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/beans https://www.springframework.org/schema/beans/spring-beans.xsd" > <bean id ="hello" class ="pojo.Hello" > <property name ="str" value ="Spring" /> </bean > </beans >
测试类MyTest
package holle1;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import pojo.Hello;public class MyTest { public static void main (String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml" ); Hello holle = (Hello) context.getBean("hello" ); System.out.println(holle.toString()); } }
核心用set注入,所以必须要有下面的se()方法
public void setStr (String str) { this .str = str; }
思考:
IoC:对象由Spring 来创建,管理,装配!
弹幕评论里面的理解:
原来这套程序是:你写好菜单买好菜,客人来了自己把菜炒好招待,就相当于你请人吃饭 现在这套程序是:你告诉楼下餐厅,你要哪些菜,客人来的时候,餐厅把做好的你需要的菜送上来 IoC:炒菜这件事,不再由你自己来做,而是委托给了第三方__餐厅来做
此时的区别就是,如果我还需要做其他的菜,我不需要自己搞菜谱买材料再做好,而是告诉餐厅,我要什么菜,什么时候要,你做好送来
.
在前面第一个module试试引入Spring
<?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/beans https://www.springframework.org/schema/beans/spring-beans.xsd" > <bean id ="userDaomSql" class ="dao.UserDaoMysqlImpl" > </bean > <bean id ="userServiceImpl" class ="service.UserServiceImp" > <property name ="userDao" ref ="userDaomSql" /> </bean > </beans >
第一个module改良后测试
package holle0;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import service.UserServiceImpl;public class MyTest0 { public static void main (String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml" ); UserServiceImpl userServiceImpl = (UserServiceImpl) context.getBean("userServiceImpl" ); userServiceImpl.getUser(); } }
总结:
所有的类都要装配的beans.xml 里面;
所有的bean 都要通过容器去取;
容器里面取得的bean,拿出来就是一个对象,用对象调用方法即可;
4、IoC创建对象的方式
使用无参构造创建对象,默认。
使用有参构造(如下)
下标赋值
index指的是有参构造中参数的下标,下标从0开始;
<?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/beans https://www.springframework.org/schema/beans/spring-beans.xsd" > <bean id ="user" class ="pojo.User" > <constructor-arg index ="0" value ="chen" /> </bean > </beans >
类型赋值(不建议使用)
<bean id ="user" class ="pojo.User" > <constructor-arg type ="java.lang.String" value ="kuang" /> </bean >
直接通过参数名(掌握)
<bean id ="user" class ="pojo.User" > <constructor-arg name ="name" value ="kuang" > </constructor-arg > </bean >
注册bean之后就对象的初始化了(**类似 new 类名()**)
弹幕评论:
name方式还需要无参构造和set方法,index和type只需要有参构造
就算是new 两个对象,也是只有一个实例(单例模式:全局唯一 )
User user = (User) context.getBean("user" ); User user2 = (User) context.getBean("user" ); system.out.println(user == user2)
总结:在配置文件加载的时候,容器(< bean>)中管理的对象就已经初始化了
5、Spring配置 5.1、别名 <bean id ="user" class ="pojo.User" > <constructor-arg name ="name" value ="chen" > </constructor-arg > </bean > <alias name ="user" alias ="userLove" />
5.2、Bean的配置 <bean id ="user" class ="pojo.User" name ="u1 u2,u3;u4" > <property name ="name" value ="chen" /> </bean >
5.3、import import一般用于团队开发使用,它可以将多个配置文件,导入合并为一个
假设,现在项目中有多个人开发,这三个人复制不同的类开发,不同的类需要注册在不同的bean中,我们可以利 用import将所有人的beans.xml合并为一个总的!
张三(beans.xm1)
李四(beans2.xm1)
王五(beans3.xm1)
applicationContext.xml
<import resource ="beans.xm1" /> <import resource ="beans2.xml" /> <import resource ="beans3.xm1" />
使用的时候,直接使用总的配置就可以了
弹幕评论:
按照在总的xml中的导入顺序来进行创建,后导入的会重写先导入的,最终实例化的对象会是后导入xml中的那个
6、依赖注入(DI) 6.1、构造器注入 第4点有提到
6.2、set方式注入【重点】 依赖注入:set注入!
依赖:bean对象的创建依赖于容器
注入:bean对象中的所有属性,由容器来注入
【环境搭建】
复杂类型
Address类
真实测试对象
Student类
beans.xml
测试
MyTest3
Student类
package pojo;import java.util.*;@Get @Set public class Student { private String name; private Address address; private String[] books; private List<String> hobbies; private Map<String, String> card; private Set<String> game; private Properties infor; private String wife; @Override public String toString () { return "Student{" +"\n" + "name='" + name + '\'' +"\n" + ", address=" + address.toString() +"\n" + ", books=" + Arrays.toString(books) +"\n" + ", hobbies=" + hobbies +"\n" + ", card=" + card +"\n" + ", game=" + game +"\n" + ", infor=" + infor +"\n" + ", wife='" + wife + '\'' +"\n" + '}' ; } }
Address类
package pojo;public class Address { private String address; public String getAddress () { return address; } public void setAddress (String address) { this .address = address; } @Override public String toString () { return "Address{" + "address='" + address + '\'' + '}' ; } }
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/beans https://www.springframework.org/schema/beans/spring-beans.xsd" > <bean id ="address" class ="pojo.Address" > <property name ="address" value ="address你好" /> </bean > <bean id ="student" class ="pojo.Student" > <property name ="name" value ="name你好" /> <property name ="address" ref ="address" /> <property name ="books" > <array > <value > 三国</value > <value > 西游</value > <value > 水浒</value > </array > </property > <property name ="hobbies" > <list > <value > 唱</value > <value > 跳</value > <value > rap</value > <value > 篮球</value > </list > </property > <property name ="card" > <map > <entry key ="username" value ="root" /> <entry key ="password" value ="root" /> </map > </property > <property name ="game" > <set > <value > wangzhe</value > <value > lol</value > <value > galname</value > </set > </property > <property name ="wife" > <null > </null > </property > <property name ="infor" > <props > <prop key ="id" > 20200802</prop > <prop key ="name" > cbh</prop > </props > </property > </bean > </beans >
MyTest3
import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import pojo.Student;public class MyTest3 { public static void main (String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml" ); Student stu = (Student) context.getBean("student" ); System.out.println(stu.toString()); } }
6.3、拓展注入 官方文档位置
pojo增加User类
package pojo;public class User { private String name; private int id; public User () { } public User (String name, int id) { super (); this .name = name; this .id = id; } public String getName () { return name; } public void setName (String name) { this .name = name; } public int getId () { return id; } public void setId (int id) { this .id = id; } @Override public String toString () { return "User [name=" + name + ", id=" + id + "]" ; } }
注意: beans 里面加上这下面两行
使用p和c命名空间需要导入xml约束
xmlns:p=“http://www.springframework.org/schema/p” xmlns:c=“http://www.springframework.org/schema/c”
?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:p ="http://www.springframework.org/schema/p" xmlns:c ="http://www.springframework.org/schema/c" xsi:schemaLocation ="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd" > <bean id ="user" class ="pojo.User" p:name ="cxk" p:id ="20" > </bean > <bean id ="user2" class ="pojo.User" c:name ="cbh" c:id ="22" > </bean > </beans >
测试
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml" ); User user = context.getBean("user" ,User.class); System.out.println(user.toString());
6.4、Bean作用域
单例模式(默认)
<bean id ="user2" class ="pojo.User" c:name ="cxk" c:age ="19" scope ="singleton" > </bean > 1
弹幕评论:单例模式是把对象放在pool中,需要再取出来,使用的都是同一个对象实例
原型模式: 每次从容器中get的时候,都产生一个新对象!
<bean id ="user2" class ="pojo.User" c:name ="cxk" c:age ="19" scope ="prototype" > </bean > 1
其余的request、session、application这些只能在web开放中使用!
7、Bean的自动装配
自动装配是Spring满足bean依赖的一种方式
Spring会在上下文自动寻找,并自动给bean装配属性
在Spring中有三种装配的方式
在xml中显示配置
在java中显示配置
隐式的自动装配bean 【重要】
环境搭建:一个人有两个宠物
byType自动装配:byType会自动查找,和自己对象set方法参数的类型相同的bean
保证所有的class唯一(类为全局唯一)
byName自动装配:byName会自动查找,和自己对象set对应的值对应的id
保证所有id唯一,并且和set注入的值一致
<bean id ="cat1" class ="pojo.Cat" /> <bean id ="cat2" class ="pojo.Cat" />
7.1测试:自动装配 pojo的Cat类
public class Cat { public void shut () { System.out.println("miao" ); } }
pojo的Dog类
public class Dog { public void shut () { System.out.println("wow" ); } }
pojo的People类
package pojo;public class People { private Cat cat; private Dog dog; private String 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; } @Override public String toString () { return "People{" + "cat=" + cat + ", dog=" + dog + ", name='" + name + '\'' + '}' ; } }
xml配置 -> 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/beans https://www.springframework.org/schema/beans/spring-beans.xsd" > <bean id ="cat" class ="pojo.Cat" /> <bean id ="dog" class ="pojo.Dog" /> <bean id ="people" class ="pojo.People" autowire ="byType" > <property name ="name" value ="cbh" > </property > </bean > </beans >
xml配置 -> byName 自动装配
<bean id ="cat" class ="pojo.Cat" /> <bean id ="dog" class ="pojo.Dog" /> <bean id ="people" class ="pojo.People" autowire ="byName" > <property name ="name" value ="cbh" > </property > </bean >
弹幕评论:byName只能取到小写,大写取不到
7.2、使用注解实现自动装配 jdk1.5支持的注解,spring2.5支持的注解
The introduction of annotation-based configuration raised the question of whether this approach is “better” than XML.(翻译:基于注释的配置的引入提出了一个问题,即这种方法是否比XML“更好”)
导入context约束
xmlns:context=”http://www.springframework.org/schema/context"
配置注解的支持:< context:annotation-config/>
<?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/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd" > <context:annotation-config /> </beans >
7.2.1、@Autowired 默认是byType方式,如果匹配不上,就会byName
在属性上个使用,也可以在set上使用
我们可以不用编写set方法了,前提是自动装配的属性在Spring容器里,且要符合ByName 自动装配
public class People { @Autowired private Cat cat; @Autowired private Dog dog; private String name; }
@Nullable 字段标记了这个注解,说明该字段可以为空
public name(@Nullable String name){
}
public @interface Autowired { boolean required () default true ; }
如果定义了Autowire的require属性为false,说明这个对象可以为null,否则不允许为空(false表示找不到装配,不抛出异常)
7.2.2、@Autowired+@Qualifier @Autowired不能唯一装配时,需要@Autowired+@Qualifier
如果@Autowired自动装配环境比较复杂。自动装配无法通过一个注解完成的时候,可以使用@Qualifier(value = “dog”)去配合使用,指定一个唯一的id对象
public class People { @Autowired private Cat cat; @Autowired @Qualifier(value = "dog") private Dog dog; private String name; }
弹幕评论:
如果xml文件中同一个对象被多个bean使用,Autowired无法按类型找到,可以用@Qualifier指定id查找
7.2.3、@Resource 默认是byName方式,如果匹配不上,就会byType
public class People { Resource(name="cat" ) private Cat cat; Resource(name="dog" ) private Dog dog; private String name; }
弹幕评论:
Autowired是byType,@Autowired+@Qualifier = byType || byName
Autowired是先byteType,如果唯一則注入,否则byName查找。resource是先byname,不符合再继续byType
区别: @Resource和@Autowired的区别:
都是用来自动装配的,都可以放在属性字段上
@Autowired通过byType的方式实现,而且必须要求这个对象存在!【常用】
@Resource默认通过byname的方式实现,如果找不到名字,则通过byType实现!如果两个都找不到的情况下,就报错!【常用】
执行顺序不同:@Autowired通过byType的方式实现。@Resource默认通过byname的方式实现
8、使用注解开发 在spring4之后,使用注解开发,必须要保证aop包的导入 使用注解需要导入contex的约束
<?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/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd" > <context:annotation-config /> </beans >
8.1、bean 弹幕评论: 有了< context:component-scan>,另一个< context:annotation-config/>标签可以移除掉,因为已经被包含进去了。
<context:component-scan base-package ="com.kuang" /> <context:annotation-config />
@Component public class User { public String name ="秦疆" ; }
8.2、属性如何注入@value @Component public class User { @value("kuangshen") public String name; public void setName (String name) { this .name = name; } }
8.3、衍生的注解 @Component有几个衍生注解,会按照web开发中,mvc架构中分层。
dao (@Repository)
service(@Service)
controller(@Controller)
这四个注解的功能是一样的,都是代表将某个类注册到容器中
8.4、自动装配置 @Autowired:默认是byType方式,如果匹配不上,就会byName
@Nullable:字段标记了这个注解,说明该字段可以为空
@Resource:默认是byName方式,如果匹配不上,就会byType
8.5、作用域@scope @Component @scope("prototype") public class User { @value("kuangshen") public String name; @value("kuangshen") public void setName (String name) { this .name = name; } }
8.6、小结 xml与注解:
xml更加万能,维护简单,适用于任何场合
注解,不是自己的类使用不了,维护复杂
最佳实践:
xml用来管理bean
注解只用来完成属性的注入
要开启注解支持
9、使用Java的方式配置Spring 不使用Spring的xml配置,完全交给java来做!
Spring的一个子项目,在spring4之后,,,它成为了核心功能
实体类:pojo的User.java
@component public class User { private String name; public String getName () { return name; } @value("QINJIANG') public void setName (String name) { this .name = name; } @Override public String toString () { return "user{" + "name='" + name + '\'' + '}' ; } }
弹幕评论:要么使用@Bean,要么使用@Component和ComponentScan,两种效果一样
配置文件:config中的kuang.java
@Import(KuangConfig2.class),用@import来包含KuangConfig2.java
@Configuration @componentScan("com.Kuang.pojo") public class KuangConfig { public User getUser () { return new User(); } }
弹幕评论:ComponentScan、@Component(“pojo”) 这两个注解配合使用
测试类
public class MyTest { public static void main (String[ ] args) { ApplicationContext context = new AnnotationConfigApplicationContext(KuangConfig.Class); User getUser =(User)context.getBean( "getUser" ); System.out.Println(getUser.getName()); } }
会创建两个相同对象问题的说明:
弹幕总结 - -> @Bean是相当于< bean>标签创建的对象,而我们之前学的@Component是通过spring自动创建的这个被注解声明的对象,所以这里相当于有两个User对象被创建了。一个是bean标签创建的(@Bean),一个是通过扫描然后使用@Component,spring自动创建的User对象,所以这里去掉@Bean这些东西,然后开启扫描。之后在User头上用@Component即可达到spring自动创建User对象了
@Configuration @componentScan("com.Kuang.pojo") public class KuangConfig { public User getUser () { return new User(); } }
弹幕评论:ComponentScan、@Component(“pojo”) 这两个注解配合使用
测试类
public class MyTest { public static void main (String[ ] args) { ApplicationContext context = new AnnotationConfigApplicationContext(KuangConfig.Class); User getUser =(User)context.getBean( "getUser" ); System.out.Println(getUser.getName()); } }
会创建两个相同对象问题的说明:
弹幕总结 - -> @Bean是相当于< bean>标签创建的对象,而我们之前学的@Component是通过spring自动创建的这个被注解声明的对象,所以这里相当于有两个User对象被创建了。一个是bean标签创建的(@Bean),一个是通过扫描然后使用@Component,spring自动创建的User对象,所以这里去掉@Bean这些东西,然后开启扫描。之后在User头上用@Component即可达到spring自动创建User对象了
10、动态代理 代理模式是SpringAOP的底层
分类:动态代理和静态代理
10.1、静态代理 代码步骤:
1、接口
package pojo;public interface Host { public void rent () ; }
2、真实角色
package pojo;public class HostMaster implements Host { public void rent () { System.out.println("房东要出租房子" ); } }
3、代理角色
package pojo;public class Proxy { public Host host; public Proxy () { } public Proxy (Host host) { super (); this .host = host; } public void rent () { seeHouse(); host.rent(); fee(); sign(); } public void seeHouse () { System.out.println("看房子" ); } public void fee () { System.out.println("收中介费" ); } public void sign () { System.out.println("签合同" ); } }
4、客户端访问代理角色
package holle4_proxy;import pojo.Host;import pojo.HostMaster;import pojo.Proxy;public class My { public static void main (String[] args) { Host host = new HostMaster(); Proxy proxy = new Proxy(host); proxy.rent(); } }
代码翻倍:几十个真实角色就得写几十个代理
AOP横向开发
10.2、动态代理 动态代理和静态角色一样,动态代理底层是反射机制
动态代理类是动态生成的,不是我们直接写好的!
动态代理(两大类):基于接口,基于类
基于接口:JDK的动态代理【使用ing】
基于类:cglib
java字节码实现:javasisit
了解两个类 1、Proxy:代理 2、InvocationHandler:调用处理程序
实例:
接口 Host.java
package pojo2;public interface Host { public void rent () ; }
接口Host实现类 HostMaster.java
package pojo2;public class HostMaster implements Host { public void rent () { System.out.println("房东要租房子" ); } }
代理角色的处理程序类 ProxyInvocationHandler.java
package pojo2;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class ProxyInvocationHandler implements InvocationHandler { public HostMaster hostMaster ; public void setHostMaster (HostMaster hostMaster) { this .hostMaster = hostMaster; } public Object getProxy () { return Proxy.newProxyInstance(this .getClass().getClassLoader(), hostMaster.getClass().getInterfaces(), this ); public Object invoke (Object proxy, Method method, Object[] args) throws Throwable { seeHouse(); Object result = method.invoke(hostMaster, args); fee(); return result; } public void seeHouse () { System.out.println("看房子" ); } public void fee () { System.out.println("收中介费" ); } }
用户类 My2.java
package holle4_proxy;import pojo2.Host;import pojo2.Host2;import pojo2.HostMaster;import pojo2.ProxyInvocationHandler;public class My2 { public static void main (String[] args) { HostMaster hostMaster = new HostMaster(); ProxyInvocationHandler pih = new ProxyInvocationHandler(); pih.setHostMaster(hostMaster); Host proxy = (Host) pih.getProxy(); proxy.rent(); } }
弹幕评论: 什么时候调用invoke方法的? 代理实例调用方法时invoke方法就会被调用,可以debug试试
改为万能代理类
public class ProxyInvocationHandler implements InvocationHandler { public Object target; public void setTarget (Object target) { this .target = target; } public Object getProxy () { return Proxy.newProxyInstance(this .getClass().getClassLoader(), target.getClass().getInterfaces(), this ); } public Object invoke (Object proxy, Method method, Object[] args) throws Throwable { Object result = method.invoke(target, args); return result; } }
11、AOP 11.1、什么是AOP
11.2、AOP在Spring中的使用 提供声明式事务,允许用户自定义切面
横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志,安全,缓存,事务等等…
切面(Aspect):横切关注点 被模块化的特殊对象。即,它是一个类。(Log类)
通知(Advice):切面必须要完成的工作。即,它是类中的一个方法。(Log类中的方法)
目标(Target):被通知对象。(生成的代理类)
代理(Proxy):向目标对象应用通知之后创建的对象。(生成的代理类)
切入点(PointCut):切面通知执行的”地点”的定义。(最后两点:在哪个地方执行,比如:method.invoke())
连接点(JointPoint):与切入点匹配的执行点。
SpringAOP中,通过Advice定义横切逻辑,Spring中支持5种类型的Advice:
即AOP在不改变原有代码的情况下,去增加新的功能。 (代理)
11.3、使用Spring实现AOP 导入jar包
<dependency > <groupId > org.aspectj</groupId > <artifactId > aspectjweaver</artifactId > <version > 1.9.4</version > </dependency >
11.3.1、方法一:使用原生spring接口 springAPI接口实现
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:aop ="http://www.springframework.org/schema/aop" xsi:schemaLocation ="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd" > <bean id ="userservice" class ="service.UserServiceImpl" /> <bean id ="log" class ="log.Log" /> <bean id ="afterLog" class ="log.AfterLog" /> <aop:config > <aop:pointcut id ="pointcut" expression ="execution(* service.UserServiceImpl.*(..))" /> <aop:advisor advice-ref ="log" pointcut-ref ="pointcut" /> <aop:advisor advice-ref ="afterLog" pointcut-ref ="pointcut" /> </aop:config > </beans >
execution(返回类型,类名,方法名(参数)) -> execution(* com.service., (…))
UserService.java
package service;public interface UserService { public void add () ; public void delete () ; public void query () ; public void update () ; }
UserService 的实现类 UserServiceImp.java
package service;public class UserServiceImpl implements UserService { public void add () { System.out.println("add增" ); } public void delete () { System.out.println("delete删" ); } public void update () { System.out.println("update改" ); } public void query () { System.out.println("query查" ); } }
前置Log.java
package log;import org.springframework.aop.MethodBeforeAdvice;import java.lang.reflect.Method;public class Log implements MethodBeforeAdvice { public void before (Method method, Object[] args, Object target) throws Throwable { System.out.println(target.getClass().getName()+"的" +method.getName()+"被执行了" ); } }
后置AfterLog.java
package log;import java.lang.reflect.Method;import org.springframework.aop.AfterReturningAdvice;public class AfterLog implements AfterReturningAdvice { public void afterReturning (Object returnValue, Method method, Object[] args, Object target) throws Throwable { System.out.println("执行了" +method.getName()+"方法,返回值是" +returnValue); } }
测试类MyTest5
import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import service.UserService;public class MyTest5 { public static void main (String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml" ); UserService userService = (UserService) context.getBean("userservice" ); userService.add(); } }
11.3.2、方法二:自定义类实现AOP <?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/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd" > <bean id ="userservice" class ="service.UserServiceImpl" /> <bean id ="log" class ="log.Log" /> <bean id ="afterLog" class ="log.AfterLog" /> <bean id ="diy" class ="diy.DiyPointcut" /> <aop:config > <aop:aspect ref ="diy" > <aop:pointcut id ="point" expression ="execution(* service.UserServiceImpl.*(..))" /> <aop:before method ="before" pointcut-ref ="point" /> <aop:after method ="after" pointcut-ref ="point" /> </aop:aspect > </aop:config > </beans >
package diy;public class DiyPointcut { public void before () { System.out.println("插入到前面" ); } public void after () { System.out.println("插入到后面" ); } }
public class MyTest5 { public static void main (String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml" ); UserService userService = (UserService) context.getBean("userservice" ); userService.add(); } }
11.3.3、方法三:使用注解实现 <?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/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd" > <bean id ="userservice" class ="service.UserServiceImpl" /> <bean id ="diyAnnotation" class ="diy.DiyAnnotation" > </bean > <aop:aspectj-autoproxy /> </beans >
DiyAnnotation.java
package diy;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;@Aspect public class DiyAnnotation { @Before("execution(* service.UserServiceImpl.*(..))") public void before () { System.out.println("=====方法执行前=====" ); } @After("execution(* service.UserServiceImpl.*(..))") public void after () { System.out.println("=====方法执行后=====" ); } @Around("execution(* service.UserServiceImpl.*(..))") public void around (ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("环绕前" ); Object proceed = joinPoint.proceed(); System.out.println("环绕后" ); } }
测试
public class MyTest5 { public static void main (String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml" ); UserService userService = (UserService) context.getBean("userservice" ); userService.add(); } }
输出结果:
12、整合mybatis mybatis-spring官网:https://mybatis.org/spring/zh/
mybatis的配置流程:
编写实体类
编写核心配置文件
编写接口
编写Mapper.xmi
测试
12.1、mybatis-spring-方式一
编写数据源配置
sqISessionFactory
sqISessionTemplate(相当于sqISession)
需要给接口加实现类【new】
将自己写的实现类,注入到Spring中
测试!
先导入jar包
<dependencies > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-webmvc</artifactId > <version > 5.2.7.RELEASE</version > </dependency > <dependency > <groupId > org.aspectj</groupId > <artifactId > aspectjweaver</artifactId > <version > 1.9.4</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-jdbc</artifactId > <version > 5.2.7.RELEASE</version > </dependency > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis</artifactId > <version > 3.5.2</version > </dependency > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis-spring</artifactId > <version > 2.0.4</version > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > 8.0.12</version > </dependency > <dependency > <groupId > org.projectlombok</groupId > <artifactId > lombok</artifactId > <version > 1.18.12</version > </dependency > </dependencies > <build > <resources > <resource > <directory > src/main/java</directory > <includes > <include > **/*.properties</include > <include > **/*.xml</include > </includes > <filtering > false</filtering > </resource > <resource > <directory > src/main/resources</directory > <includes > <include > **/*.properties</include > <include > **/*.xml</include > </includes > <filtering > false</filtering > </resource > </resources > </build >
编写顺序: User -> UserMapper -> UserMapper.xml -> spring-dao.xml -> UserServiceImpl -> applicationContext.xml -> MyTest6
代码步骤:
pojo实体类 User
package pojo;import lombok.Data;@Data public class User { private int id; private String name; private String pwd; }
mapper目录下的 UserMapper、UserMapperImpl、UserMapper.xml
接口UserMapper
package mapper;import java.util.List;import pojo.User;public interface UserMapper { public List<User> getUser () ; }
UserMapperImpl
package mapper;import java.util.List;import org.mybatis.spring.SqlSessionTemplate;import pojo.User;public class UserMapperImpl implements UserMapper { private SqlSessionTemplate sqlSessionTemplate; public void setSqlSessionTemplate (SqlSessionTemplate sqlSessionTemplate) { this .sqlSessionTemplate = sqlSessionTemplate; } public List<User> getUser () { UserMapper mapper = sqlSessionTemplate.getMapper(UserMapper.class); return mapper.getUser(); } }
UserMapper.xml (狂神给面子才留下来的)
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace ="mapper.UserMapper" > <select id ="getUser" resultType ="pojo.User" > select * from mybatis.mybatis </select > </mapper >
resource目录下的 mybatis-config.xml、spring-dao.xml、applicationContext.xml
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd" > <configuration > <settings > <setting name ="logImpl" value ="STDOUT_LOGGING" /> </settings > <typeAliases > <package name ="pojo" /> </typeAliases > </configuration >
spring-dao.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:aop ="http://www.springframework.org/schema/aop" xsi:schemaLocation ="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd" > <bean id ="datasource" class ="org.springframework.jdbc.datasource.DriverManagerDataSource" > <property name ="driverClassName" value ="com.mysql.cj.jdbc.Driver" /> <property name ="url" value ="jdbc:mysql://127.0.0.1:3306/mybatis?useSSL=false& useUnicode=true& characterEncoding=utf-8& serverTimezone=Asia/Shanghai" /> <property name ="username" value ="root" /> <property name ="password" value ="root" /> </bean > <bean id ="sqlSessionFactory" class ="org.mybatis.spring.SqlSessionFactoryBean" > <property name ="dataSource" ref ="datasource" /> <property name ="configLocation" value ="classpath:mybatis-config.xml" /> <property name ="mapperLocations" value ="classpath:mapper/*.xml" /> </bean > <bean id ="sqlSession" class ="org.mybatis.spring.SqlSessionTemplate" > <constructor-arg index ="0" ref ="sqlSessionFactory" /> </bean > </beans >
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:aop ="http://www.springframework.org/schema/aop" xsi:schemaLocation ="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd" > <import resource ="spring-dao.xml" /> <bean id ="userMapper" class ="mapper.UserMapperImpl" > <property name ="sqlSessionTemplate" ref ="sqlSession" > </property > </bean > </beans >
测试类
import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import mapper.UserMapper;import pojo.User;public class MyTest6 { public static void main (String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml" ); UserMapper userMapper = (UserMapper) context.getBean("userMapper" ); for (User user : userMapper.getUser()) { System.out.println(user); } } }
12.2、mybatis-spring-方式二 UserServiceImpl2
package mapper;import pojo.User;import org.apache.ibatis.session.SqlSession;import org.mybatis.spring.support.SqlSessionDaoSupport;import java.util.List;public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper { public List<User> getUser () { SqlSession sqlSession = getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); return mapper.getUser(); } }
spring-dao.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:aop ="http://www.springframework.org/schema/aop" xsi:schemaLocation ="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd" > <bean id ="datasource" class ="org.springframework.jdbc.datasource.DriverManagerDataSource" > <property name ="driverClassName" value ="com.mysql.cj.jdbc.Driver" /> <property name ="url" value ="jdbc:mysql://127.0.0.1:3306/mybatis?useSSL=false& useUnicode=true& characterEncoding=utf-8& serverTimezone=Asia/Shanghai" /> <property name ="username" value ="root" /> <property name ="password" value ="root" /> </bean > <bean id ="sqlSessionFactory" class ="org.mybatis.spring.SqlSessionFactoryBean" > <property name ="dataSource" ref ="datasource" /> <property name ="configLocation" value ="classpath:mybatis-config.xml" /> <property name ="mapperLocations" value ="classpath:mapper/*.xml" /> </bean > </beans >
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:aop ="http://www.springframework.org/schema/aop" xsi:schemaLocation ="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd" > <import resource ="spring-dao.xml" /> <bean id ="userMapper2" class ="mapper.UserMapperImpl2" > <property name ="sqlSessionFactory" ref ="sqlSessionFactory" > </property > </bean > </beans >
测试
public class MyTest6 { public static void main (String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml" ); UserMapper userMapper = (UserMapper) context.getBean("userMapper2" ); for (User user : userMapper.getUser()) { System.out.println(user); } } }