spring
Author:Aaron
Version:9.0.2
一、引言1.1 原生web开发中存在哪些问题?二、Spring框架2.1 概念2.2 访问与下载三、Spring架构组成四、自定义工厂4.1 配置文件4.2 工厂类五、构建Maven项目5.1 新建项目5.2 选择Maven目录5.3 GAV坐标六、Spring环境搭建6.1 pom.xml中引入Spring常用依赖6.2 创建Spring配置文件七、Spring工厂编码八、依赖与配置文件详解8.1 Spring依赖关系8.2 schema九、IOC(Inversion of Control )控制反转【重点
】9.1 项目中强耦合问题9.2 解决方案十、DI(Dependency Injection)依赖注入【重点
】10.1 概念10.2 Set注入10.2.1 定义目标Bean类型10.2.2 基本类型 + 字符串类型 + 日期类型10.2.3 容器类型10.2.4 自建类型10.3 构造注入【了解】10.3.1 定义目标Bean类型10.3.2 注入10.4 自动注入【了解】十一、Bean细节11.1 控制简单对象的单例、多例(原型)模式11.2 FactoryBean创建复杂对象【了解】11.2.1 实现FactoryBean接口11.2.2 配置spring-context.xml11.2.3 特例十二、Spring工厂特性12.1 饿汉式创建优势12.2 生命周期方法12.3 生命周期注解 12.4 生命周期阶段十三、代理设计模式13.1 概念13.2 静态代理设计模式 13.3 动态代理设计模式13.3.1 JDK动态代理实现(基于接口)13.3.2 CGlib动态代理实现(基于继承)十四、面向切面编程【重点
】14.1 概念14.2 作用14.3 AOP开发术语14.4 环境搭建14.5 开发流程14.6 AOP小结14.7 通知类【可选】 14.8 通配切入点14.9 JDK和CGLIB选择14.10 后处理器14.10.1 后处理器定义14.10.2 配置后处理器14.10.3 bean生命周期十五、Spring + MyBatis【重点
】15.1 配置数据源15.1.1 创建数据库和表 15.1.2 整合Spring配置文件和properties配置文件15.1.3 dao接口和pojo实体15.1.4 service接口和实现类15.1.5 Druid监控中心(了解)15.1.6 测试监控中心(了解)15.2 整合MyBatis15.2.1 配置SqlSessionFactory15.2.2 配置MapperScannerConfigurer15.2.3 配置Service15.2.4 测试十六、声明式事务【重点
】16.1 事务属性16.1.1 隔离级别16.1.1.1 概念16.1.1.2 特性16.1.1.3 并发问题16.1.2 传播行为16.1.3 读写性16.1.4 事务超时16.1.5 事务回滚16.2 配置DataSourceTransactionManager16.3 配置事务通知16.4 编织16.5 测试十七、注解开发17.1 开启注解17.2 声明bean17.3 注入(DI)17.4 注解所需配置17.5 事务控制17.6 AOP开发17.6.1 配置17.6.2 注解使用十八、集成JUnit18.1 导入依赖18.2 编码
一、引言
1.1 原生web开发中存在哪些问题?
传统Web开发存在硬编码所造成的过度程序耦合(例如:Service中作为属性的Dao对象)。
部分Java EE API较为复杂,使用效率低(例如:JDBC开发步骤)。
侵入性强,移植性差(例如:DAO实现的更换,从Connection到SqlSession)。
二、Spring框架
2.1 概念
Spring是一个项目管理框架,同时也是一套Java EE解决方案。
Spring是众多优秀设计模式的组合(工厂、单例、代理、适配器、包装器、观察者、模板、策略)。
Spring并未替代现有框架产品,而是将众多框架进行有机整合,简化企业级开发,俗称"胶水框架"。
2.2 访问与下载
官方网站:https://spring.io/
下载地址:http://repo.spring.io/release/org/springframework/spring/
三、Spring架构组成
Spring架构由诸多模块组成,可分类为
核心技术:
测试:模拟对象,TestContext框架,Spring MVC测试,WebTestClient。
数据访问:
Spring MVC和 Spring WebFlux Web框架。
集成:远程处理,JMS,JCA,JMX,电子邮件,任务,调度,缓存。
语言:Kotlin,Groovy,动态语言。
Spring架构组成 |
---|
GroupId | ArtifactId | 说明 |
---|---|---|
org.springframework | ||
org.springframework | ||
org.springframework | ||
org.springframework | ||
org.springframework | ||
org.springframework | ||
org.springframework | ||
org.springframework | spring-instrument | JVM 引导的仪表(监测器)代理 |
org.springframework | spring-instrument-tomcat | Tomcat 的仪表(监测器)代理 |
org.springframework | spring-jdbc | 支持包括数据源设置和 JDBC 访问支持 |
org.springframework | spring-jms | 支持包括发送/接收JMS消息的助手类 |
org.springframework | spring-messaging | 对消息架构和协议的支持 |
org.springframework | spring-orm | 对象/关系映射,包括对 JPA 和 Hibernate 的支持 |
org.springframework | spring-oxm | 对象/XML 映射(Object/XML Mapping,OXM) |
org.springframework | ||
org.springframework | ||
org.springframework | ||
org.springframework | ||
org.springframework | spring-webmvc-portlet | 用于 Portlet 环境的MVC实现 |
org.springframework | spring-websocket | WebSocket 和 SockJS 实现,包括对 STOMP 的支持 |
org.springframework |
四、自定义工厂
4.1 配置文件
项目resources目录下创建bean.properties文件
userDao=com.qf.dao.UserDAOImpl
userService=com.qf.service.UserServiceImpl
4.2 工厂类
/**
* 自定义工厂
*/
public class MyFactory {
private Properties properties = new Properties();
public MyFactory(){}
public MyFactory(String config) throws IOException {
// 加载配置文件
properties.load(MyFactory.class.getResourceAsStream(config));
}
// 获取对象
public Object getBean(String beanName) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
// 获得类路径
String classPath = properties.getProperty(beanName);
if(classPath!=null){
Class claz = null;
// 反射:加载类对象
claz = Class.forName(classPath);
// 反射:获得对象
return claz.newInstance();
}
return null;
}
public static void main(String[] args) throws Exception {
// 创建工厂对象
MyFactory myFactory = new MyFactory("/bean.properties");
// 从工厂中获取对象
UserDao userDao = (UserDao)myFactory.getbean("userDao");
UserService userService = (UserService)myFactory.getbean("userService");
userDao.selectUserAll();
userService.findUserAll();
}
}
五、构建Maven项目
5.1 新建项目
使用IDEA打开已创建的文件夹目录 |
---|
5.2 选择Maven目录
选择Maven项目 |
---|
5.3 GAV坐标
GAV坐标 |
---|
六、Spring环境搭建
6.1 pom.xml中引入Spring常用依赖
6.2 创建Spring配置文件
命名无限制,约定俗成命名有:spring-context.xml、applicationContext.xml、beans.xml
七、Spring工厂编码
定义目标Bean类型
public class MyClass{
public void show(){
System.out.println("HelloWorld");
}
}
spring-context.xml中的< beans >内部配置bean标签
<!-- 配置实例(id:“唯一标识” class="需要被创建的目标对象全限定名") -->
<bean id="mc" class="com.qf.spring.part1.factory.MyClass" />
调用Spring工厂API(ApplicationContext接口)
public class TestFactory{
/**
* 程序中的对象都交由Spring的ApplicationContext工厂进行创建。
*/
public static void main(String[] args){
//1. 读取配置文件中所需创建的bean对象,并获得工厂对象
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-context.xml");
//2. 通过id获取bean对象
MyClass mc = (MyClass) ctx.getBean("mc");
//3. 使用对象
mc.show();
}
}
八、依赖与配置文件详解
Spring框架包含多个模块,每个模块各司其职,可结合需求引入相关依赖Jar包实现功能。
8.1 Spring依赖关系
Spring常用功能的Jar包依赖关系 |
---|
8.2 schema
配置文件中的顶级标签中包含了语义化标签的相关信息
xmlns:语义化标签所在的命名空间。
xmlns:xsi:XMLSchema-instance 标签遵循Schema标签标准。
xsi:schemaLocation:xsd文件位置,用以描述标签语义、属性、取值范围等。
九、IOC(Inversion of Control )控制反转【重点
】
Inverse Of Controll:控制反转
反转了依赖关系的满足方式,由之前的自己创建依赖对象,变为由工厂推送。(变主动为被动,即反转)
解决了具有依赖关系的组件之间的强耦合,使得项目形态更加稳健
IOC是什么? IOC(Inversion of Control)控制反转,IOC是一种新的Java编程模式,目前很多轻量级容器都在广泛使用的模式。
IOC解决了什么问题? 在IOC出现以前,组件之间的协调关系是由程序内部代码来控制的,或者说,以前我们使用New关键字来实现两组间之间的依赖关系的。这种方式就造成了组件之间的互相耦合。IOC(控制反转)就是来解决这个问题的,它将实现组件间的关系从程序内部提到外部容器来管理。也就是说,由容器在运行期将组件间的某种依赖关系动态的注入组件中。
9.1 项目中强耦合问题
public class UserDAOImpl implements UserDAO{....}
public class UserServiceImpl implements UserService {
// !!!强耦合了UserDAOImpl!!!,使得UserServiceImpl变得不稳健!!
private UserDAO userDAO= new UserDAOImpl();
9.2 解决方案
// 不引用任何一个具体的组件(实现类),在需要其他组件的位置预留存取值入口(set/get)
public class UserServiceImpl implements UserService {
// !!!不再耦合任何DAO实现!!!,消除不稳健因素!!
private UserDAO userDAO;
// 为userDAO定义set/get,允许userDAO属性接收spring赋值
//Getters And Setters
<bean id="userDAO" class="com.qf.spring.part1.injection.UserDaoImpl"></bean>
<!-- UserServiceImpl组件 -->
<bean id="userService" class="com.qf.spring.part1.injection.UserServiceImpl">
<!-- 由spring为userDAO属性赋值,值为id="userDAO"的bean -->
<property name="userDAO" ref="userDAO"/>
</bean>
此时,如果需要更换其他UserDAO实现类,则UserServiceImpl不用任何改动!
则此时的UserServiceImpl组件变得更加稳健!
十、DI(Dependency Injection)依赖注入【重点
】
IoC的实现方式 及 与DI的关系?
-
依赖查找(Dependency Lookup):容器中的受控对象通过容器的API来查找自己所依赖的资源和协作对象。 这种方式虽然降低了对象间的依赖,但是同时也使用到了容器的API,造成了我们无法在容器外使用和测试对象。 依赖查找是一种更加传统的IoC实现方式。
-
依赖注入(Dependency Injection):这就是DI,字面上理解,依赖注入就是将服务注入到使用它的地方。对象只提供普通的方法让容器去决定依赖关系, 容器全权负责组件的装配,它会把符合依赖关系的对象通过属性(JavaBean中的setter)或者是构造传递给需要的对象。 相对于IoC而言,依赖注入(DI)更加准确地描述了IoC的设计理念。所谓依赖注入,即组件之间的依赖关系由容器在应用系统运行期来决定, 也就是由容器动态地将某种依赖关系的目标对象实例注入到应用系统中的各个关联的组件之中。
Spring中的IoC与DI:
-
IoC是Spring的核心,贯穿始终。对于Spring框架来说,就是由Spring来负责控制对象的生命周期和对象间的关系。
-
Spring中DI有两种注入方式:
-
Setter方式(传值方式)
-
构造器方式(引用方式)。
-
10.1 概念
在Spring创建对象的同时,为其属性赋值,称之为依赖注入。
10.2 Set注入
创建对象时,Spring工厂会通过Set方法为对象的属性赋值。
10.2.1 定义目标Bean类型
public class User {
private Integer id;
private String password;
private String sex;
private Integer age;
private Date bornDate;
private String[] hobbys;
private Set<String> phones;
private List<String> names;
private Map<String,String> countries;
private Properties files;
//Getters And Setters
}
10.2.2 基本类型 + 字符串类型 + 日期类型
<bean id="u1" class="com.qf.spring.part1.injection.User">
<!--base field-->
<property name="id" value="1001" />
<property name="password" value="123456" />
<property name="sex" value="male" />
<property name="age" value="20" />
<property name="bornDate" value="1990/1/1" /><!--注意格式"/"-->
</bean>
10.2.3 容器类型
<bean id="u1" class="com.qf.spring.part1.injection.User">
<!--Array-->
<property name="hobbys">
<array>
<value>Run</value>
<value>Swim</value>
<value>Climb</value>
</array>
</property>
<!--Set-->
<property name="phones">
<set>
<value>13777777777</value>
<value>13888888888</value>
<value>13999999999</value>
</set>
</property>
<!--List-->
<property name="names">
<list>
<value>tom</value>
<value>jack</value>
<value>marry</value>
</list>
</property>
<!--Map-->
<property name="countries">
<map>
<entry key="CN" value="China" />
<entry key="US" value="America" />
<entry key="KR" value="Korea" />
</map>
</property>
<!--Properties-->
<property name="files">
<props>
<prop key="first">One</prop>
<prop key="second">Two</prop>
<prop key="third">Three</prop>
</props>
</property>
</bean>
10.2.4 自建类型
public class Address {
private String position;
private String zipCode;
//....get() And set().....
}
<!--次要bean,被作为属性-->
<bean id="addr" class="com.qf.spring.part1.injection.Address">
<property name="position" value="北京市海淀区" />
<property name="zipCode" value="100001" />
</bean>
<!--主要bean,操作的主体-->
<bean id="u2" class="com.qf.spring.part1.injection.User">
<property name="address" ref="addr" /><!--address属性引用addr对象-->
</bean>
<!--次要bean,被作为属性-->
<bean id="userDao" class="com.qf.spring.part1.injection.UserDaoImpl" />
<!--主要bean,操作的主体-->
<bean id="userService" class="com.qf.spring.part1.injection.UserServiceImpl">
<property name="ud" ref="userDao" /><!--ud属性引用userDao对象-->
</bean>
10.3 构造注入【了解】
创建对象时,Spring工厂会通过构造方法为对象的属性赋值。
10.3.1 定义目标Bean类型
public class Student {
private Integer id;
private String name;
private String sex;
private Integer age;
//Constructors
public Student(Integer id , String name , String sex , Integer age){
this.id = id;
this.name = name;
this.sex = sex;
this.age = age;
}
}
10.3.2 注入
<!--构造注入-->
<bean id="u3" class="com.qf.zcg.spring.day1.t2.ioc.Student">
<constructor-arg name="id" value="1234" /> <!-- 除标签名称有变化,其他均和Set注入一致 -->
<constructor-arg name="name" value="tom" />
<constructor-arg name="age" value="20" />
<constructor-arg name="sex" value="male" />
</bean>
10.4 自动注入【了解】
不用在配置中 指定为哪个属性赋值,及赋什么值.
由spring自动根据某个 "原则" ,在工厂中查找一个bean,为属性注入属性值
public class UserServiceImpl implements UserService {
private UserDAO userDAO;
//Getters And Setters
....
}
<bean id="userDao" class="com.qf.spring.part1.injection.UserDaoImpl" />
<!-- 为UserServiceImpl中的属性基于类型自动注入值 -->
<bean id="userService" class="com.qf.spring.part1.injection.UserServiceImpl" autowire="byType"></bean>
<bean id="userDao" class="com.qf.spring.part1.injection.UserDaoImpl" />
<!-- 为UserServiceImpl中的属性基于类型自动注入值 -->
<bean id="userService" class="com.qf.spring.part1.injection.UserServiceImpl" autowire="byName"></bean>
十一、Bean细节
11.1 控制简单对象的单例、多例(原型)模式
配置< bean scope="singleton | prototype" />
<!--
singleton(默认):每次调用工厂,得到的都是同一个对象。
prototype:每次调用工厂,都会创建新的对象。
-->
<bean id="mc" class="com.qf.zcg.spring.day1.t1.basic.MyClass" scope="singleton" />
-
注意:需要根据场景决定对象的单例、多例模式。
-
(单例)可以共用:Service、DAO、SqlSessionFactory(或者是所有的工厂)。
-
(多例)不可共用:Connection、SqlSession、ShoppingCart。
11.2 FactoryBean创建复杂对象【了解】
作用:让Spring可以创建复杂对象、或者无法直接通过反射创建的对象。
FactoryBean解决复杂对象创建 |
---|
11.2.1 实现FactoryBean接口
接口方法描述 |
---|
-
注意:isSingleton方法的返回值,需根据所创建对象的特点决定返回true/false。
-
例如:Connection 不应该被多个用户共享,返回false。
-
例如:SqlSessionFactory 重量级资源,不该过多创建,返回true+。
11.2.2 配置spring-context.xml
配置与获取方式 |
---|
11.2.3 特例
获取FactoryBean接口的实现类对象,而非getObject()所生产的对象。 |
---|
十二、Spring工厂特性
12.1 饿汉式创建优势
工厂创建之后,会将Spring配置文件中的所有对象都创建完成(饿汉式)。
提高程序运行效率。避免多次IO,减少对象创建时间。(概念接近连接池,一次性创建好,使用时直接获取)
12.2 生命周期方法
自定义初始化方法:添加“init-method”属性,Spring则会在创建对象之后,调用此方法。
自定义销毁方法:添加“destroy-method”属性,Spring则会在销毁对象之前,调用此方法。
销毁:工厂的close()方法被调用之后,Spring会毁掉所有已创建的单例对象。
分类:Singleton对象由Spring容器销毁、Prototype对象由JVM销毁。
12.3 生命周期注解
初始化注解、销毁注解
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
12.4 生命周期阶段
单例bean:singleton
随工厂启动
多例bean:prototype
被使用时
十三、代理设计模式
13.1 概念
将核心功能与辅助功能(事务、日志、性能监控代码)分离,达到核心业务功能更纯粹、辅助业务功能可复用。
功能分离 |
---|
13.2 静态代理设计模式
通过代理类的对象,为原始类的对象(目标类的对象)添加辅助功能,更容易更换代理实现类、利于维护。
静态代理 |
---|
-
代理类 = 实现原始类相同接口 + 添加辅助功能 + 调用原始类的业务方法。
-
租房接口
public interface FangDongService {
public void zufang();
}
-
租房实现类
// 原始业务类
public class FangDongServiceImpl implements FangDongService{
-
静态代理类 = 实现原始类相同接口 + 添加辅助功能 + 调用原始类的业务方法
// 静态代理类
public class FangDongProxy implements FangDongService{
private FangDongService fangDongService = new FangDongServiceImpl();
-
测试类
public class ProxyTest {
public static void main(String[] args) {
FangDongProxy fangDongProxy = new FangDongProxy();
fangDongProxy.zufang();
}
}
-
静态代理的问题
-
代理类数量过多,不利于项目的管理。
-
多个代理类的辅助功能代码冗余,修改时,维护性差。
-
13.3 动态代理设计模式
动态创建代理类的对象,为原始类的对象添加辅助功能。
字节码是在运行期动态生成
13.3.1 JDK动态代理实现(基于接口)
public class DynamicProxyTest {
13.3.2 CGlib动态代理实现(基于继承)
public class DynamicProxyTest {
十四、面向切面编程【重点
】
14.1 概念
AOP(Aspect Oriented Programming),即面向切面编程,利用一种称为"横切"的技术,剖开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。
14.2 作用
Spring的AOP编程即是通过动态代理类为原始类的方法添加辅助功能。
14.3 AOP开发术语
连接点(Joinpoint):连接点是程序类中客观存在的方法,可被Spring拦截并切入内容。
切入点(Pointcut):被Spring切入连接点。
通知、增强(Advice):可以为切入点添加额外功能,分为:前置通知、后置通知、异常通知、环绕通知等。
目标对象(Target):代理的目标对象(真实对象)
引介(Introduction)[了解]:一种特殊的增强,可在运行期为类动态添加Field和Method。
织入(Weaving):把通知应用到具体的类,进而创建新的代理类的过程。
代理(Proxy):被AOP织入通知后,产生的结果类。
切面(Aspect):由切点和通知组成,将横切逻辑织入切面所指定的连接点中。
14.4 环境搭建
引入AOP相关依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
spring-context.xml引入AOP命名空间
14.5 开发流程
定义原始类
public interface UserService {
public List<User> queryUsers();
public Integer updateUser(User user);
public Integer saveUser(User user);
public Integer deleteUser(Integer id);
}
public class UserServiceImpl implements UserService {
定义通知类(添加额外功能)
-
前置通知类
/**
* 前置通知类
*/
public class MyBeforeAdvice implements MethodBeforeAdvice {
-
后置通知,在核心之后执行,如果核心有异常,则不执行
/**
* 后置通知,在核心之后执行,如果核心有异常,则不执行
*/
public class MyAfterAdvice implements AfterReturningAdvice {
-
环绕通知, 在核心功能前后都执行辅助功能
/**
* 环绕通知
*/
public class MyMethodInterceptor implements MethodInterceptor {
-
异常通知, 在核心中抛异常时,执行
/**
* 在核心中抛异常时,执行
*/
public class MyThrowsAdvice implements ThrowsAdvice {
public void afterThrowing(Exception ex){
System.out.println("my throws 异常通知辅助功能");
}
}
定义bean标签
<!-- 目标 : 原始业务-->
<bean id="us" class="com.qf.service.UserServiceImpl" />
<!-- 通知:额外功能 -->
<!-- 前置通知类 -->
<bean id="before" class="com.qf.aop.MyBeforeAdvice"></bean>
<!-- 后置通知,在核心之后执行,如果核心有异常,则不执行 -->
<bean id="after" class="com.qf.aop.MyAfterAdvice"></bean>
<!-- 在核心中抛异常时,执行 -->
<bean id="throws" class="com.qf.aop.MyThrowsAdvice"></bean>
<!-- 环绕通知 -->
<bean id="mi" class="com.qf.aop.MyMethodInterceptor"></bean>
定义切入点(PointCut)
形成切面(Aspect)
<aop:config>
<!-- 切入点【修饰符 返回值 包.类 方法名 参数表 】 -->
<aop:pointcut id="pc_shine" expression="execution(* queryUsers())"/>
<aop:pointcut id="pc_shine2" expression="execution(* deleteUser(..))"/>
<aop:pointcut id="pc_shine3" expression="execution(* updateUser(..))"/>
<aop:pointcut id="pc_shine4" expression="execution(* saveUser(..))"/>
<!-- 组装 -->
<aop:advisor advice-ref="before" pointcut-ref="pc_shine"/>
<aop:advisor advice-ref="after" pointcut-ref="pc_shine2"/>
<aop:advisor advice-ref="throws" pointcut-ref="pc_shine3"/>
<aop:advisor advice-ref="mi" pointcut-ref="pc_shine4"/>
</aop:config>
测试代码
public class ProcessorTest {
14.6 AOP小结
通过AOP提供的编码流程,更便利的定制切面,更方便的定制了动态代理。
进而彻底解决了辅助功能冗余的问题;
业务类中职责单一性得到更好保障;
辅助功能也有很好的复用性。
14.7 通知类【可选】
定义通知类,达到通知效果0
前置通知:MethodBeforeAdvice
后置通知:AfterReturningAdvice //有异常不执行,方法会因异常而结束,无返回值
异常通知:ThrowsAdvice
环绕通知:MethodInterceptor, 注意:在环绕中必须调用原始方法
14.8 通配切入点
根据表达式通配切入点
<aop:config>
<!--匹配参数-->
<aop:pointcut id="pc01" expression="execution(* *(com.qf.pojo.User))"/>
<!--匹配任意方法(无参)-->
<aop:pointcut id="pc02" expression="execution(* *())"/>
<!--匹配方法名(任意参数)-->
<aop:pointcut id="pc03" expression="execution(* saveUser(..))"/>
<!--匹配返回值类型(任意参数)-->
<aop:pointcut id="pc04" expression="execution(java.lang.Integer *(..))"/>
<!--匹配类名(任意参数)-->
<aop:pointcut id="pc05" expression="execution(* com.qf.service.UserServiceImpl.*(..))"/>
<!--匹配包名(任意参数)-->
<aop:pointcut id="pc06" expression="execution(* com.qf.service.*.*(..))"/>
<!--匹配包名、以及子包名(任意参数)-->
<aop:pointcut id="pc07" expression="execution(* com..*.*(..))"/>
<!--组装-->
<aop:advisor advice-ref="after" pointcut-ref="pc01"/>
</aop:config>
14.9 JDK和CGLIB选择
spring底层,包含了jdk代理和cglib代理两种动态代理生成机制
基本规则是:目标业务类如果有接口则用JDK代理,没有接口则用CGLib代理
class DefaultAopProxyFactory{
// 该方法中明确定义了 JDK代理和CGLib代理的选取规则
// 基本规则是:目标业务类如果有接口则用JDK代理,没有接口则用CGLib代理
public AopProxy createAopProxy(){...}
}
14.10 后处理器
spring中定义了很多后处理器;
每个bean在创建完成之前 ,都会有一个后处理过程,即再加工,对bean做出相关改变和调整;
spring-AOP中,就有一个专门的后处理器,负责通过原始业务组件(Service),再加工得到一个代理组件。
后处理器是一种特殊的Bean,实现了BeanPostProcessor接口,该接口包含两个方法,bean在初始化的时候都会执行
常用后处理器 |
---|
14.10.1 后处理器定义
/**
* 定义bean后处理器
* 作用:在bean的创建之后,进行再加工
*/
public class MyBeanPostProcessor implements BeanPostProcessor{
/**
* 在bean的init方法之前执行
* @param bean 原始的bean对象
* @param beanName
* @return
* @throws BeansException
*/
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("后处理器 在init之前执行~~~"+bean.getClass());
return bean;
}
/**
* 在bean的init方法之后执行
* @param bean postProcessBeforeInitialization返回的bean
* @param beanName
* @return
* @throws BeansException
*/
14.10.2 配置后处理器
<!-- 配置后处理器,将对工厂中所有的bean声明周期进行干预 -->
<bean class="com.qf.aop.MyBeanPostProcessor"></bean>
14.10.3 bean生命周期
构造 》 注入属性 满足依赖 》 后处理器前置过程 》 初始化 》后处理器后置过程 》 返回 》 销毁
十五、Spring + MyBatis【重点
】
15.1 配置数据源
将数据源配置到项目中
引入pom.xml中依赖
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
<!-- Spring整合mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>
<!-- MyBatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<!-- mysql驱动 依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.25</version>
<scope>runtime</scope>
</dependency>
<!-- 连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<