简介
Spring5框架
内容介绍:
1.Spring概念
2.IOC容器
3.Aop
4.JDBCTEmplate
5.事物管理
6.Spring5新特性
所需的jar包
参考俺滴下面博客
Spring所需jar包_爱你的阿白~的博客-CSDN博客
一.Spring框架概述
1.概述
1.Spring框架是轻量级的JavaEE框架
2.Spring可以解决企业应用开发的复杂性
3.Spring有两个核心部分:IOC和Aop
(1)IOC:控制反转,把创建对象的过程交给Spring进行管理
(2)Aop:面向切面,不修改源代码进行功能增强
4.Spring特点
(1)方便解耦,简化开发
(2)Aop变成支持
(3)方便程序测试
(4)方便和其他框架进行整合
(5)方便进行事物操作
(6)降低API开发难度
5.Spring5
2.入门案例
(1)下载spring
最后是这个网址
https://repo.spring.io/ui/native/release/org/springframework/spring/
下载解压
(2)创建新的项目
(3)导入jar包
把所需的jar包导入其中
导入流程:
在项目文件夹中建立lab文件夹
把jar包放入文件夹中
(4)创建普通类
在这个类中创建普通方法
(5)创建Spring配置文件
在配置文件中配置创建的对象
1.Spring配置文件使用xml文件格式
(6)测试代码编写
二,IOC容器
1.IOC底层原理
(1)什么是IOC
控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。
one:控制反转,把对象的创建和对象的调用过程交给Spring进行管理
two:使用IOC的目的:为了耦合度降低
three:做入门案例就是IOC的实现
(2)IOC底层原理
(1)xml解析,工厂模式,反射
(3)画图讲解IOC底层原理
IOC过程
(1)配置xml文件,配置创建的对象
(2)有service类和dao类,创建工厂类
2.IOC接口(BeanFactory)
1.IOC思想基于IOC容器完成,IOC容器底层就是对象工厂
2.Spring提供IOC容器实现的两种方式:(两个接口)
(1)BeanFactory:
IOC容器中最基本实现方式,时Spring内部使用的接口,不提供开发人员进行使用
特点:加载配置文件的时候不会去创建对象,在获取对象(使用)才会去创建对象
(2)ApplicationContext:
BeanFactory接口的子接口,提供更多更强大的功能,一般有开发人员进行使用
特点:加载配置文件时候就会把在配置文件的对象进行创建
3.ApplicationContext接口有实现类
FlieSystemXmlApplicationContext对应电脑的盘符路径
ClassPathXmlApplicationContext类路径
3.IOC操作Bean管理(基于xml)
(1)Bean管理定义:
Bean管理指的是两个操作
1.Spring创建对象
2.Spring注入属性
(2)Bean管理操作的两种方式
1.基于xml方式创建对象2.基于注解方式的实现
1.基于xml配置文件方式的实现
<!--配置User对象创建--> <bean id = "user" class="com.spring.User"></bean>
(1)在Spring中使用bean标签,在标签里面添加对应的属性,就可以实现对象的创建
(2)在bean标签中有许多的属性,介绍常用的属性
*id属性:唯一标识
*class属性:类全路径(包类路径)
*name属性:和id一样,但是在name中可以加入些特殊符号
(3)创建对象的时候,默认是执行无参数构造方法
2.基于xml方式注入属性
(1)DI:依赖注入,就是注入属性
3.第一种注入方式:使用set方法进行注入
(1)创建类,定义属性和对应的set方法
(2)在Spring配置文件配置对象的创建,配置属性注入
最后测试:
4.第二种注入方式:通过有参构造注入
(1)创建类,定义属性,创建属性对应有参数构造方法
(2)在Spring文件中进行配置
测试:
5.p名称空间注入(了解)
(1)使用P名称空间注入,可以简化基于xml配置方式
第一步:添加p名称空间在配置文件中
第二步:进行属性注入,在bean标签里面进行操作
测试:
(3)IOC操作Bean管理(xml注入其他类型的操作)
字面量
one:null值
eg:
测试:
two:属性值包含特殊符号
1.把<>进行转义<>
2.把带特殊符号内容写到CDATA
测试:(两个的输出结果都一样)
three:注入属性-外部bean
1.创建两个类service和dao类
2.在service调用dao里面的方法
3.在Spring配置文件中进行配置
测试:
four:注入属性-内部bean
一对多关系:部门和员工
一个部门有多个员工,一个员工属于一个部门
部门是一,员工是多
在实体类之间表示一对多的关系,员工表示所属部门,使用对象类型属性进行表示
在Spring的配置文件中进行配置
测试:
five:注入属性-级联赋值
1.第一种写法
测试:
2.第二种写法
Dept.java
Testbean.java同上
测试:
(4)IOC操作Bean管理(xml注入集合属性)
注入数组类型属性
注入List集合类型属性
注入Map集合类型属性
1.创建类
定义数组,List,Map,Set类型的属性,生成对应的set方法
package com.spring.collectiontype;import java.nio.MappedByteBuffer;import java.util.Arrays;import java.util.List;import java.util.Map;import java.util.Set;/** * @author yanchaochao * @date 2022/3/17 20:34 */public class Stu { //1.数组类型 private String[] courses; //2.list集合类型属性 private List<String> list; //3.创建Map集合属性 private Map<String,String> maps; //4.set集合类型 private Set<String> sets; public void setCourses(String[] courses) { this.courses = courses; } public void setList(List<String> list) { this.list = list; } public void setMaps(Map<String, String> maps) { this.maps = maps; } public void setSets(Set<String> sets) { this.sets = sets; } //测试 public void test(){ System.out.println(Arrays.toString(courses)); System.out.println(list); System.out.println(maps); System.out.println(sets); }}
2.在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 http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--1.集合类型属性注入--> <bean id="stu" class="com.spring.collectiontype.Stu"> <!--数组类型属性注入--> <property name="courses"> <array> <value>java</value> <value>c</value> <value>c++</value> <value>算法</value> <value>mysql</value> </array> </property> <!--list类型属性注入--> <property name="list"> <list> <value>张三</value> <value>小三</value> </list> </property> <!--map类型属性注入--> <property name="maps"> <map> <entry key="JAVA" value="java"></entry> <entry key="C" value="c"></entry> </map> </property> <!--set类型属性注入--> <property name="sets"> <set> <value>MySQL</value> <value>Redis</value> </set> </property> </bean></beans>
测试:
package com.spring.testdemo;import com.spring.collectiontype.Stu;import org.junit.Test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;/** * @author yanchaochao * @date 2022/3/17 21:19 */public class Testcollectiontype { @Test public void testCollection(){ ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml"); Stu stu = context.getBean("stu", Stu.class); stu.test(); }}
3.在集合里设置对象类型值
<!--创建多个course对象--> <bean id="course1" class="com.spring.collectiontype.Course"> <property name="cname" value="Spring5框架"></property> </bean> <bean id="course2" class="com.spring.collectiontype.Course"> <property name="cname" value="MySQL数据库"></property> </bean>
<!--注入list集合类型,值是对象--> <property name="courseList"> <list> <ref bean="course1"></ref> <ref bean="course2"></ref> </list> </property>
Course.java
package com.spring.collectiontype;/** * @author yanchaochao * @date 2022/3/17 21:40 */public class Course { private String cname;//课程名称 public void setCname(String cname) { this.cname = cname; } @Override public String toString() { return "Course{" + "cname='" + cname + '\'' + '}'; }}
Stu.java
package com.spring.collectiontype;import java.nio.MappedByteBuffer;import java.util.Arrays;import java.util.List;import java.util.Map;import java.util.Set;/** * @author yanchaochao * @date 2022/3/17 20:34 */public class Stu { //1.数组类型 private String[] courses; //2.list集合类型属性 private List<String> list; //3.创建Map集合属性 private Map<String,String> maps; //4.set集合类型 private Set<String> sets; //学生所学多门课程 private List<Course>courseList; public void setCourseList(List<Course> courseList) { this.courseList = courseList; } public void setCourses(String[] courses) { this.courses = courses; } public void setList(List<String> list) { this.list = list; } public void setMaps(Map<String, String> maps) { this.maps = maps; } public void setSets(Set<String> sets) { this.sets = sets; } //测试 public void test(){ System.out.println(Arrays.toString(courses)); System.out.println(list); System.out.println(maps); System.out.println(sets); System.out.println(courseList); }}
bean1.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:lang="http://www.springframework.org/schema/lang" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang.xsd"> <!--1.集合类型属性注入--> <bean id="stu" class="com.spring.collectiontype.Stu"> <!--数组类型属性注入--> <property name="courses"> <array> <value>java</value> <value>c</value> <value>c++</value> <value>算法</value> <value>mysql</value> </array> </property> <!--list类型属性注入--> <property name="list"> <list> <value>张三</value> <value>小三</value> </list> </property> <!--map类型属性注入--> <property name="maps"> <map> <entry key="JAVA" value="java"></entry> <entry key="C" value="c"></entry> </map> </property> <!--set类型属性注入--> <property name="sets"> <set> <value>MySQL</value> <value>Redis</value> </set> </property> <!--注入list集合类型,值是对象--> <property name="courseList"> <list> <ref bean="course1"></ref> <ref bean="course2"></ref> </list> </property> </bean> <!--创建多个course对象--> <bean id="course1" class="com.spring.collectiontype.Course"> <property name="cname" value="Spring5框架"></property> </bean> <bean id="course2" class="com.spring.collectiontype.Course"> <property name="cname" value="MySQL数据库"></property> </bean></beans>
Testcollectiontype.java
package com.spring.testdemo;import com.spring.collectiontype.Stu;import org.junit.Test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;/** * @author yanchaochao * @date 2022/3/17 21:19 */public class Testcollectiontype { @Test public void testCollection(){ ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml"); Stu stu = context.getBean("stu", Stu.class); stu.test(); }}
测试:
4.把集合注入的部分提取出来
(1)在spring配置文件中引入名称空间util
(2)使用util标签完成list集合注入提取
Book.java
package com.spring.collectiontype;import java.util.List;/** * @author yanchaochao * @date 2022/3/17 21:55 */public class Book { private List<String>list; public void setList(List<String> list) { this.list = list; } public void test(){ System.out.println(list); }}
bean2.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:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> <!--1.提取list集合类型注入--> <util:list id="booklist"> <value>JAVA</value> <value>C</value> <value>MySQL</value> <value>C++</value> <value>Git</value> </util:list> <!--2.提取list集合类型属性注入使用--> <bean id="book" class="com.spring.collectiontype.Book"> <property name="list" ref="booklist"></property> </bean></beans>
测试:
package com.spring.testdemo;import com.spring.collectiontype.Book;import com.spring.collectiontype.Stu;import org.junit.Test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;/** * @author yanchaochao * @date 2022/3/17 22:03 */public class TestBook { @Test public void testBook(){ ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml"); Book book = context.getBean("book", Book.class); book.test(); }}
(5)IOC操作Bean管理(FactoryBean)
Spring有两种类型Bean,一种普通bean,另外一种工厂bean(FactoryBean)
普通Bean:在配置文件中定义Bean类型就是返回类型
工厂Bean:在配置文件定义Bean类型可以和返回类型不一样
第一步:创建类,让这个类作为工厂bean,实现接口FactoryBean
第二步:实现接口里面的方法,在实现的方法中定义返回的bean类型
MyBean.java
package com.spring.factorybean;import com.spring.collectiontype.Course;import org.springframework.beans.factory.FactoryBean;/** * @author yanchaochao * @date 2022/3/17 22:21 */public class MyBean implements FactoryBean<Course> { //定义类型和返回类型不一样 //定义返回bean @Override public Course getObject() throws Exception { Course course = new Course(); course.setCname("abc"); return course; } @Override public Class<?> getObjectType() { return null; } @Override public boolean isSingleton() { return FactoryBean.super.isSingleton(); }}
bean3.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:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> <bean id="myBean" class="com.spring.factorybean.MyBean"> </bean></beans>
测试:
package com.spring.testdemo;import com.spring.collectiontype.Course;import com.spring.collectiontype.Stu;import com.spring.factorybean.MyBean;import org.junit.Test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;/** * @author yanchaochao * @date 2022/3/17 22:23 */public class Testfactorybean { @Test public void testFactoryBean(){ ApplicationContext context = new ClassPathXmlApplicationContext("bean3.xml"); Course course = context.getBean("myBean", Course.class); System.out.println(course); }}
(6)IOC操作Bean管理(Bean的作用域)
1.在Spring里面,设置创建Bean实例时单实例还是多实例
2.在Spring里面,默认情况下,bean是单实例对象
由图可得出,输出的两个地址是一样的,所以可以得出在默认情况下bean是单实例对象
3.如何设置单实例还是多实例
(1)在Spring配置文件bean标签里面有属性用于设置单实例还是多实例
(2)scope属性值
第一个值 默认值,singleton,表示单实例对象
第二个值 prototype,表示多实例对象
测试:
两个对象的地址不一样
(3)singleton和prototype区别
singleton表示单实例,prototype表示多实例
设置scope值是singleton时候,加载spring的时候就会创建单实例对象
设置scope值是prototype时候,不是在加载spring配置文件时候创建对象,在调用getBean方法创建多实例对象
(7)IOC操作Bean管理(生命周期)
1.生命周期
从对象到对象销毁的过程
2.bean生命周期
(1)通过构造器创建bean实例(无参数构造)
(2)为bean的属性设置值和对其他bean的引用(调用set方法)
(3)调用bean的初始化的方法(需要进行配置)
(4)bean可以直接使用了(对象获取到了)
(5)当容器关闭时候,调用bean的销毁的方法(需要进行配置销毁)
3.演示bean的生命周期
Order.java
package com.spring.bean;/** * @author yanchaochao * @date 2022/3/18 19:48 */public class Order { private String oname; //无参数构造 public Order(){ System.out.println("第一步,执行无参构造实例"); } public void setOname(String oname) { this.oname = oname; System.out.println("第二步,调用set方法调用初始化值"); } //创建执行初始化的方法 public void initMethod(){ System.out.println("第三部,执行初始化方法"); } //执行销毁的方法 public void destroyMethod(){ System.out.println("第五步执行销毁的方法"); }}
bean4.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:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> <bean id="orders" class="com.spring.bean.Order" init-method="initMethod" destroy-method="destroyMethod"> <property name="oname" value="手机"></property> </bean></beans>
测试:
Testbean.java
package com.spring.testdemo;import com.spring.bean.Order;import com.spring.collectiontype.Book;import org.junit.Test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;/** * @author yanchaochao * @date 2022/3/18 19:54 */public class Testbean { @Test public void testBook(){ ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml"); Order order = context.getBean("orders", Order.class); System.out.println("第四步,得到对象"); System.out.println(order); //手动销毁 context.close(); }}
4.bean的后置处理
(1)通过构造器创建bean实例(无参数构造)
(2)为bean的属性设置值和对其他bean的引用(调用set方法)
(3)把bean实例传递bean后置处理器的方法
postProcessBeforeInitialization
(4)调用bean的初始化的方法(需要进行配置)
(5)把bean实例传递bean后置处理器的方法
postProcessAfterInitialization
(6)bean可以直接使用了(对象获取到了)
(7)当容器关闭时候,调用bean的销毁的方法(需要进行配置销毁)
5.演示添加后置处理器效果
(1)创建类,实现接口BeanPostProcessor,创建后置处理器
MyBeanPost.java
package com.spring.bean;import org.springframework.beans.BeansException;import org.springframework.beans.factory.config.BeanPostProcessor;import org.springframework.lang.Nullable;/** * @author yanchaochao * @date 2022/3/18 20:17 */public class MyBeanPost implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("在初始化之前执行的方法"); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("在初始化之后执行的方法"); return bean; }}
Order.java
package com.spring.bean;/** * @author yanchaochao * @date 2022/3/18 19:48 */public class Order { private String oname; //无参数构造 public Order(){ System.out.println("第一步,执行无参构造实例"); } public void setOname(String oname) { this.oname = oname; System.out.println("第二步,调用set方法调用初始化值"); } //创建执行初始化的方法 public void initMethod(){ System.out.println("第三部,执行初始化方法"); } //执行销毁的方法 public void destroyMethod(){ System.out.println("第五步执行销毁的方法"); }}
bean4.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:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> <bean id="orders" class="com.spring.bean.Order" init-method="initMethod" destroy-method="destroyMethod"> <property name="oname" value="手机"></property> </bean> <!--配置后置处理器--> <bean id="myBeanPost" class="com.spring.bean.MyBeanPost"></bean></beans>
Testbean.java
package com.spring.testdemo;import com.spring.bean.Order;import com.spring.collectiontype.Book;import org.junit.Test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;/** * @author yanchaochao * @date 2022/3/18 19:54 */public class Testbean { @Test public void testBook(){ ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml"); Order order = context.getBean("orders", Order.class); System.out.println("第四步,得到对象"); System.out.println(order); //手动销毁 context.close(); }}
(8)IOC操作Bean管理(xml自动装配)
1.什么是自动装配
(1)根据指定装配规则(属性名称或者属性类型),spring自动将匹配的属性值进行注入
2.演示自动装配
(1)根据属性名称自动注入
<!--实现自动装配 bean标签属性autowire,配置自动装配 autowire属性常用两个值: byName根据属性名称注入,注入值bean的id值和类属性名称一样 byType根据属性类型注入 --> <bean id="emp" class="com.spring.autowire.Emp" autowire="byName">
根据属性名称注入,注入值bean的id值和类属性名称一样
(2)根据属性类型自动注入
<!--实现自动装配 bean标签属性autowire,配置自动装配 autowire属性常用两个值: byName根据属性名称注入,注入值bean的id值和类属性名称一样 byType根据属性类型注入 --> <bean id="emp" class="com.spring.autowire.Emp" autowire="byType">
(9)IOC操作Bean管理(外部属性文件)
1.直接配置数据库信息
(1)配置德鲁伊连接池
<!--直接配置连接池--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/userDb" /> <property name="username" value="root" /> <property name="password" value="root" /> </bean>
2.引入外部属性文件配置数据库连接池
(1)创建外部属性文件,properties格式文件,写数据库信息
(2)把外部properties属性文件引入到配置文件
*引入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:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
(3)在spring配置文件中使用标签引入外部属性文件
<!--引入外部属性文件--><context:property-placeholder location="classpath*:jdbc.properties"></context:property-placeholder><!--配置连接池--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close"> <property name="driverClassName" value="${prop.driverClass}" /> <property name="url" value="${prop.url}" /> <property name="username" value="${prop.username}" /> <property name="password" value="${prop.password}" /> </bean>
4.IOC操作Bean管理(基于注解)
1.什么是注解
(1)注解是代码特殊标记,格式:@注解名称(属性名称=属性值,属性名称=属性值)
(2)使用注解,注解作用在类上面,方法上面,属性上面
(3)使用注解目的:简化xml配置
2.Spring针对Bean管理中创建对象提供注解
(1)@Component
(2)@Service
(3)@Controller
(4)@Repository
*上面四个注解功能是一样的,都可以用来创建bean实例
3.基于注解方式实现对象创建
(1)引入依赖
(2)开启组件扫描
(3)创建类,在类上面添加创建对象注解
package com.atguigu.spring5.testdemo;import com.atguigu.spring5.service.UserService;import org.junit.Test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;/** * @author yanchaochao * @date 2022/3/22 14:31 */public class TestSpring5Demo1 { @Test public void testService(){ ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml"); UserService userService = context.getBean("userService", UserService.class); System.out.println(userService); userService.add(); }}
实例一:
实例二:
4.基于注解方式实现属性注入
(1)@AutoWired:根据属性类型自动装配
第一步:把service和dao对象创建,在service和dao类添加创建对象注解
第二步:在service注入dao对象,在service类添加dao类型属性,在属性上面使用注解
@Servicepublic class UserService { //定义dao类型的属性 //不需要添加set方法 //添加注入属性注解 @Autowired private UserDao userDao; public void add(){ System.out.println("service add....."); userDao.add(); }}
UserDao.java
package com.atguigu.spring5.dao;public interface UserDao { public void add();}
UserDaoImpl
import org.springframework.stereotype.Repository;@Repositorypublic class UserDaoImpl implements UserDao{ @Override public void add(){ System.out.println("dao add..."); }}
UserService.java
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import org.springframework.stereotype.Service;@Servicepublic class UserService { //定义dao类型的属性 //不需要添加set方法 //添加注入属性注解 @Autowired private UserDao userDao; public void add(){ System.out.println("service add....."); userDao.add(); }}
测试:
TestSpring5Demo1.java
package com.atguigu.spring5.testdemo;import com.atguigu.spring5.service.UserService;import org.junit.Test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class TestSpring5Demo1 { @Test public void testService(){ ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml"); UserService userService = context.getBean("userService", UserService.class); System.out.println(userService); userService.add(); }}
(2)@Qualifier:根据属性名称进行注入
这个@Qualifier注解的使用,和上面@Autowired一起使用
(3)@Resource:可以根据类型注入,可以根据名称注入
(4)@Value:注入普通类型属性
5.完全注解开发
(1)创建配置类,替代xml的配置文件
package com.atguigu.spring5.config;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.Configuration;@Configuration //作为配置类,替代xml配置文件@ComponentScan(basePackages = {"com.atguigu"})public class SpringConfig {}
(2)编写测试类
@Test public void testService2(){ //加载配置类 ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class); UserService userService = context.getBean("userService", UserService.class); System.out.println(userService); userService.add(); }
三,AOP
1.简介
AOP(面向切面编程)
AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
主要功能
日志记录,性能统计,安全控制,事务处理,异常处理等等。
主要意图
将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。
eg:
2.底层原理
一,AOP底层使用动态代理
(1)有两种情况
第一种:有接口的情况,使用JDK代理
创建接口实现代理对象,增强类的方法
第二种:没有接口的情况,使用CGLIB代理
创建子类的代理对象,增强类的方法
3.AOP(JDK动态代理)
一,使用JDK动态代理,使用Proxy类里面的方法创建代理对象
调用newProxyInstance方法
方法里有三个参数:
one:类加载器
two:增强方法所在的类,这个类实现的接口,支持多个接口
three:实现这个接口InvocationHandler,创建代理对象,写增强的方法
二,JDK动态代理代码
(1)创建接口,定义方法
package com.study;public interface UserDao { public int add(int a,int b); public String update(String id);}
(2)创建接口实现类,实现方法
package com.study;public class UserDaoImpl implements UserDao{ @Override public int add(int a, int b) { System.out.println("add方法执行了......"); return a+b; } @Override public String update(String id) { System.out.println("update方法执行了......"); return id; }}
(3)使用Proxy类创建接口代理对象
package com.study;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.util.Arrays;/** * @author yanchaochao * @date 2022/3/22 20:39 */public class JDKProxy { public static void main(String[] args) { //创建接口实现类代理对象 Class [] interfaces = {UserDao.class}; UserDaoImpl userDao = new UserDaoImpl(); UserDao dao =(UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao)); int result = dao.add(1,2); System.out.println("result:"+result); }}//创建代理对象代码class UserDaoProxy implements InvocationHandler{ //1.把创建的是谁的代理对象,把谁传递过来 //有参数构造传递 private Object object; public UserDaoProxy(Object object){ this.object = object; } //增强的逻辑 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //方法之前 System.out.println("方法之前执行......"+method.getName()+":传递参数..."+ Arrays.toString(args)); //被增强的方法 Object res = method.invoke(object, args); //方法之后 System.out.println("方法执行之后......"+object); return res; }}
结果:
4.AOP(术语)
一,连接点
二,切入点
三,通知(增强)
四,切面
5.AOP操作(准备)
1.Spring框架一般基于AspectJ实现AOP操作
(1)什么是AspectJ
*AspectJ不是Spring组成部分,独立AOP框架,一般把AspectJ和Spring框架一起使用,进行AOP操作
2.基于AspectJ实现AOP操作
(1)基于xml配置文件实现
(2)jiyu注解方式实现
3.在项目工程里面引入AOP相关依赖
4.切入点表达式
(1)切入点表达式作用:知道对哪个类型里面的哪个方法进行增强
(2)语法结构:
execution([权限修饰符] [返回类型] [类全路径] [方法名称] [参数列表])
举例1:对com.atguigu.dao.BookDao类里面的add进行增强
execution(*com.atguigu.dao.BookDao.add(...方法中的参数))
举例2:对com.atguigu.dao.BookDao类里面的所有方法进行增强
execution(*com.atguigu.dao.BookDao. * (...方法中的参数))
举例3:对com.atguigu.dao包里面的所有类,类里面的所有方法进行增强
execution(*com.atguigu.dao. *. * (...方法中的参数))
6.AOP操作(AspectJ注解)
1.创建类,在类里面定义方法
2.创建增强类(编写增强逻辑)
(1)在增强类里面,创建方法,让不同方法代表不同通知类型
package com.study.aopanno;import org.springframework.stereotype.Component;//被增强的类@Componentpublic class User { public void add (){ System.out.println("add..."); }}
package com.study.aopanno;import org.aspectj.lang.annotation.Aspect;import org.springframework.stereotype.Component;//增强的类@Component@Aspect //生成代理对象public class UserProxy { //前置通知 public void before(){ System.out.println("before......"); }}
3.进行通知的配置
(1)在spring配置文件中,开启注解扫描
bean1.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:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--开启注解扫描--> <context:component-scan base-package="com.study.aopanno"></context:component-scan> </beans>
(2)使用注解创建User和UserProxy对象
(3)在增强类上面添加注解@Aspect
(4)在spring配置文件中开启代理生成对象
<!--开启Aspect生成的代理对象--><aop:aspectj-autoproxy></aop:aspectj-autoproxy>
4.配置不用类型的通知
(1)在增强类的里面,在作为通知方法上面添加通知类型注解,使用切入点表达式配置
package com.study.aopanno;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.*;import org.springframework.stereotype.Component;/** * @author yanchaochao * @date 2022/3/23 17:34 *///增强的类@Component@Aspect //生成代理对象public class UserProxy { //前置通知 //Before注解表示为前置通知 @Before(value = "execution(* com.study.aopanno.User.add(..))") public void before(){ System.out.println("before......"); } //最终通知 @After(value = "execution(* com.study.aopanno.User.add(..))") public void after(){ System.out.println("after......"); } //后置通知(返回通知) @AfterReturning(value = "execution(* com.study.aopanno.User.add(..))") public void afterReturning(){ System.out.println("afterReturning......"); } //异常通知 @AfterThrowing(value = "execution(* com.study.aopanno.User.add(..))") public void afterThrowing(){ System.out.println("afterThrowing......"); } //环绕通知 @Around(value = "execution(* com.study.aopanno.User.add(..))") public void around(ProceedingJoinPoint proceedingJoinPoint)throws Throwable{ System.out.println("环绕之前......"); //被增强的方法 proceedingJoinPoint.proceed(); System.out.println("环绕之后......"); }}
TestAop.java
package com.study.test;import com.study.aopanno.User;import jdk.jfr.StackTrace;import org.springframework.context.ApplicationContext;import org.junit.Test;import org.springframework.context.support.ClassPathXmlApplicationContext;public class TestAop { @Test public void testAopAnno(){ ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml"); User user = context.getBean("user", User.class); user.add(); }}
5.公共切入点抽取
package com.study.aopanno;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.*;import org.springframework.stereotype.Component;//增强的类@Component@Aspect //生成代理对象public class UserProxy { //相同切入点抽取 @Pointcut(value = "execution(* com.study.aopanno.User.add(..))") public void piontdemo(){ } //前置通知 //Before注解表示为前置通知 @Before(value = "piontdemo()") public void before(){ System.out.println("before......"); } //最终通知 @After(value = "execution(* com.study.aopanno.User.add(..))") public void after(){ System.out.println("after......"); } //后置通知(返回通知) @AfterReturning(value = "execution(* com.study.aopanno.User.add(..))") public void afterReturning(){ System.out.println("afterReturning......"); } //异常通知 @AfterThrowing(value = "execution(* com.study.aopanno.User.add(..))") public void afterThrowing(){ System.out.println("afterThrowing......"); } //环绕通知 @Around(value = "execution(* com.study.aopanno.User.add(..))") public void around(ProceedingJoinPoint proceedingJoinPoint)throws Throwable{ System.out.println("环绕之前......"); //被增强的方法 proceedingJoinPoint.proceed(); System.out.println("环绕之后......"); }}
6.有多个增强类多同一个方法进行增强,设置增强类优先级
(1)在增强类上面添加注解@Order(数字类类值),数字类值越小优先级越高
PersonPerxy.java
package com.study.aopanno;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.springframework.core.annotation.Order;import org.springframework.stereotype.Component;@Component@Aspect@Order(1)public class PersonPerxy { //后置通知(返回通知) @Before(value = "execution(* com.study.aopanno.User.add(..))") public void afterReturning(){ System.out.println("Person Before......"); }}
User.java
package com.study.aopanno;import org.springframework.stereotype.Component;//被增强的类@Componentpublic class User { public void add (){ System.out.println("add..."); }}
UserProxy.java
package com.study.aopanno;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.*;import org.springframework.core.annotation.Order;import org.springframework.stereotype.Component;//增强的类@Component@Aspect //生成代理对象@Order(3)public class UserProxy { //相同切入点抽取 @Pointcut(value = "execution(* com.study.aopanno.User.add(..))") public void piontdemo(){ } //前置通知 //Before注解表示为前置通知 @Before(value = "piontdemo()") public void before(){ System.out.println("before......"); } //最终通知 @After(value = "execution(* com.study.aopanno.User.add(..))") public void after(){ System.out.println("after......"); } //后置通知(返回通知) @AfterReturning(value = "execution(* com.study.aopanno.User.add(..))") public void afterReturning(){ System.out.println("afterReturning......"); } //异常通知 @AfterThrowing(value = "execution(* com.study.aopanno.User.add(..))") public void afterThrowing(){ System.out.println("afterThrowing......"); } //环绕通知 @Around(value = "execution(* com.study.aopanno.User.add(..))") public void around(ProceedingJoinPoint proceedingJoinPoint)throws Throwable{ System.out.println("环绕之前......"); //被增强的方法 proceedingJoinPoint.proceed(); System.out.println("环绕之后......"); }}
测试:
package com.study.test;import com.study.aopanno.User;import jdk.jfr.StackTrace;import org.springframework.context.ApplicationContext;import org.junit.Test;import org.springframework.context.support.ClassPathXmlApplicationContext;public class TestAop { @Test public void testAopAnno(){ ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml"); User user = context.getBean("user", User.class); user.add(); }}
7.AOP操作(AspectJ配置文件)
(1)创建两个类,增强类和被增强类,创建方法
package com.study.aopxml;public class Book { public void buy(){ System.out.println("buy......."); }}
package com.study.aopxml;public class BookProxy { public void Before(){ System.out.println("before......."); }}
(2)在spring配置文件中创建两个类对象
(3)在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" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><!-- 创建对象 --> <bean id="book" class="com.study.aopxml.Book"></bean> <bean id="bookProxy" class="com.study.aopxml.BookProxy"></bean><!--配置AOP增强--> <aop:config> <!--切入点--> <aop:pointcut id="p" expression="execution(* com.study.aopxml.Book.buy(..))"/> <!--配置切面--> <aop:aspect ref="bookProxy"> <!--增强作用在具体的方法上--> <aop:before method="Before" pointcut-ref="p"></aop:before> </aop:aspect> </aop:config></beans>
测试:
@Test public void testBook(){ ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml"); Book book = context.getBean("book", Book.class); book.buy(); }
完全使用注解开发
不需要创建xml文件
package com.study.config;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.EnableAspectJAutoProxy;@Configuration@ComponentScan(basePackages = {"com.study"})@EnableAspectJAutoProxy(proxyTargetClass = true)public class ConfigAop { }