循环依赖
A依赖B B依赖A
- 问题产生
- 先创建A对象并实例化,此时A对象中的B对象属性为空,填充B属性
- 当容器中没有B对象则使其实例化,此时B对象中的A对象属性为空,填充A
- 从容器中找不到则创建
- 致此就形成循环依赖问题
解决问题
- 解决问题的核心问题则在于实例化与初始化分开进行操作
- 分析getSingleton()的整个过程,Spring首先从一级缓存singletonObjects中获取。
- 如果获取不到,并且对象正在创建中,就再从二级缓存earlySingletonObjects中获取。
- 如果还是获取不到且允许singletonFactories通过getObject()获取,就从三级缓存singletonFactory.getObject()(三级缓存)获取,
- 如果获取到了则:
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
三级缓存分别指: ```java /* 单例对象的缓存: bean name —> bean instance / private final Map
singletonObjects = new ConcurrentHashMap (256);
/* 早期单例对象的缓存: bean name —> bean instance 提前暴光的单例对象的Cache 。【用于检测循环引用,与singletonFactories(三级缓存)互斥】/
private final Map
/* 单例工厂的缓存: bean name —> ObjectFactory /
private final Map
- 怎么检测是否存在循环依赖
- Bean在创建的时候可以给该Bean打标,如果递归调用回来发现正在创建中的话,即说明了循环依赖了。
- Spring中循环依赖场景有:<br />(1)构造器的循环依赖<br />(2)field属性的循环依赖。
<a name="j3N4I"></a>
## Bean实例化(装配/生命周期)过程()
- 实例化Bean
- 通过反射的特性生成对象
- 填充Bean的属性
- populateBean(), 循环依赖问题(三级缓存)
- 调用aware接口相关的方法
- invokeAwareMethod(完成BeanName,BeanFactory,BeanClassLoader对象的属性设置)
- 调用BeanPostProcessor中的前置处理方法
- (使用比较多的有ApplicationContextPostProcessor, 设置ApplicationContext, Environment, ResourceLoader, EmbeddValueResolve等对象)
- 调用initmethod方法,
- invokeinitmethod()判断是否实现了initializingBean接口, 如果有则调用afterPropertiesSet()方法
- 调用BeanPostProcessor的后置处理方法
- aop在此实现, AbstractAutoProxyCreator注册Destuction相关的回调接口
- 调用BeanFactory的getBean()方法来进行对象的获取
- 销毁流程
- 调用DisposableBean的destroy();
- 调用定制的destroy-method方法;
![image.png](https://cdn.nlark.com/yuque/0/2022/png/2480472/1647249232098-a05fb02c-678a-48cd-96e0-7331bde5c427.png#clientId=u1beb51dc-3ae6-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=372&id=jm9Ad&margin=%5Bobject%20Object%5D&name=image.png&originHeight=372&originWidth=786&originalType=binary&ratio=1&rotation=0&showTitle=false&size=79988&status=done&style=none&taskId=ude1c1c42-1dad-4aa5-99c5-8a58084a41a&title=&width=786)
<a name="PZkSK"></a>
# IOC
Ioc—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。
1. 控制反转,
1. **降低耦合**
1. 把对象的创建和对象之间的调用交给Spring管理,
1. Spring反向控制应用程序所需要使用的外部资源
2. xml解析、工厂模式、反射
<a name="jI68m"></a>
## IOC(BeanFactory)底层原理
1. IOC思想基于IOC容器完成,IOC容器底层就是对象工厂
1. Spring提供IOC容器实现两种方式:
1. BeanFactory:IOC容器基本实现,是Spring内部使用的接口,不提供开发人员使用 **加载配置文件时不会创建对象,只有在使用对象时才会创建对象**
1. ApplicationContext:BeanFactory接口的子接口,提供更多更改强大的功能,一般由开发人员使用**加载配置文件时就会创建对象**
1. ApplicationContext实现类:
- FileSystemXmlApplicationContext 文件路径加载
- ClassPathXmlApplicationContext 类加载
<a name="f4aa9842"></a>
#### ApplicationContext 与 BeanFactory 的区别
1. BeanFactory创建的bean采用延迟加载的形式,使用时创建
1. ApplicationContext在BeanFactory基础上构建,除了拥有BeanFactory的所有特性,它还支持事件发布、国际化信息的支持等。
1. ApplicationContext管理的对象会在容器初始化的时候将其全部初始化。
<a name="ef4af9ff"></a>
### IOC XML
**Bean管理是指两个操作**
<a name="5f92bea9"></a>
#### 基本标签配置
```xml
<!--配置User对象创建-->
<bean id="user" class="top.pastors.spring5.User"></bean>
- id:唯一标识 不能加特殊符号
- class:Bean的全限定名称
- name:与id功能类似 可以起多个标识 可以使用特殊字符
scope
Spring容器中的Bean是否线程安全,容器本身并没有提供Bean的线程安全策略,但是具体还是要结合具体scope的Bean去研究。Spring 的 bean 作用域(scope)类型
- singleton:单例,默认作用域。
- prototype:原型,每次创建一个新对象。
- request:请求,每次Http请求创建一个新对象,适用于WebApplicationContext环境下。
- session:会话,同一个会话共享一个实例,不同会话使用不用的实例。
- global-session:全局会话,所有会话共享一个实例。
线程安全这个问题,要从单例与原型Bean分别进行说明。
- 原型Bean
- 对于原型Bean,每次创建一个新对象,也就是线程之间并不存在Bean共享,自然是不会有线程安全的问题。
- 单例Bean
- 对于单例Bean,所有线程都共享一个单例实例Bean,因此是存在资源的竞争。
- 单例Bean,是一个无状态Bean,也就是线程中的操作不会对Bean的成员执行查询以外的操作
- 单例Bean是线程安全的。比如Spring mvc 的 Controller、Service、Dao等,这些Bean大多是无状态的,只关注于方法本身。
Bean生命周期
init-method:指定类中的初始化方法名称
destroy-method:指定类中销毁方法名称
<bean id="userDao" init-method="init" destroy-method="destroy" class="top.pastors.dao.impl.UserDaoImpl"/>
Bean实例化三种方式
- 使用无参构造方法实例化
- 它会根据默认无参构造方法来创建类对象,如果bean中没有默认无参构造函数,将会创建失败
- 工厂静态方法实例化
- 工厂的静态方法返回Bean实例
- 工厂实例方法实例化
- 工厂的非静态方法返回Bean实例
第三方Bean的配置方式
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" >
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/db1"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
DI 依赖注入
应用程序运行依赖的资源由Spring为其提供,资源进入应用程序的方式成为注入
property set方法注入(主流)
<!--1.对需要注入的变量添加set方法-->
<bean id="book" class="top.pastors.spring5.Book">
<!--3.将要注入的引用类型通过property属性进行注入
name:要注入的变量名
vlaue:属性声明标识
ref:引用类型标识
-->
<property name="bname" vlaue="易筋经"></property>
<property name="bauthor" value="达摩老祖"></property>
<property name="userDao" ref="userDaoImpl"></property>
</bean>
<!--2.如果是引用类型要将注入的资源声明为Bean-->
<bean id="userDaoImpl" class="top.pastors.spring5.UserDaoImpl" />
constructor-arg 构造方法注入
<!--1.对需要注入的变量添加构造方法-->
<bean id="book" class="top.pastors.spring5.Book">
<!--3.将要注入的引用类型通过property属性进行注入
name:参数名称 可省略 (按照顺序依次赋值)
vlaue:值
type:参数类型
index:参数索引 从0开始(与name功能相似)
-->
<constructor-arg name="bname" vlaue="易筋经"/>
<constructor-arg name="bauthor" value="达摩老祖"/>
<constructor-arg name="userDao" ref="userDaoImpl"/>
</bean>
<!--2.如果是引用类型要将注入的资源声明为Bean-->
<bean id="userDaoImpl" class="top.pastors.spring5.UserDaoImpl" />
p名称空间注入
<beans xmlns="http://www.springframework.org/schema/beans" ...>
<bean id="boot" class="top.pastors.spring5.book" p:name="九阳神功" p:author="无名氏"/>
</beans>
import 外部文件导入
如果外部引入有相同id的多个bean 新值覆盖旧址 同一个配置文件中不能配置两个相同id的bean
<import resource="applicationContext-user.xml"/>
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext-user.xml","applicationContext-book.xml");
context 外部文件导入
<!--开启context命名空间-->
<beans xmlns="http://www.springframework.org/schema/beans"... >
<context:property-placeholder location="classpath:*.properties"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" >
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
</beans>
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/db1
jdbc.username=root
jdbc.password=root
properties 外部文件导入
<!--开启context命名空间-->
<beans xmlns="http://www.springframework.org/schema/beans" ...>
<context:property-placeholder location="classpath:*.properties"/>
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
</beans>
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/db1
jdbc.username=root
jdbc.password=root
字面量
1.null值
<property name="bauthor">
<null/>
</property>
2. 属性值包含特殊符号
a. 使用转义字符
b. 把带有特殊符号的内容 <<南京>> 写到CDATA中
<property name="bauthor" >
<value><![CDATA[<<南京>>]]></value>
</property>
注入属性
外部bean
<!--beam.xml-->
<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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userService" class="top.pastors.UserService">
<!--注入UserDao对象
name:类中的属性名称
ref:创建userDao对象bean标签id值
-->
<property name="userDao" ref="userDaoImpl"></property>
</bean>
<bean id="userDaoImpl" class="top.pastors.UserDaoImpl"></bean>
</beans>
//测试
@Test
puglic void testBean(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
Emp emp = context.getBean("emp",Emp.class);
emp.add();
}
内部bean
<!--beam.xml-->
<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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="emp" class="top.pastors.Emp">
<property name="ename" value="lucy"></property>
<property name="gender" value="女"></property>
<!--配置对象类型属性-->
<property name="dept">
<bean id="dept" class="top.pastors.Dept">
<property name="dname" value="安保部"></property>
</bean>
</property>
</bean>
</beans>
//测试
@Test
puglic void testBean(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
Emp emp = context.getBean("emp",Emp.class);
emp.add();
}
级联赋值
<!--beam.xml-->
<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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="emp" class="top.pastors.Emp">
<property name="ename" value="lucy"></property>
<property name="gender" value="女"></property>
<!--配置对象类型属性-->
<property name="dept" ref="dept"></property>
<!--或者-->
<property name="dept.dname" value="财务部"></property>
</bean>
<bean id="dept" class="top.pastors.Dept">
<property name="dname" value="安保部"></property>
</bean>
</beans>
//测试
@Test
puglic void testBean(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
Emp emp = context.getBean("emp",Emp.class);
emp.add();
}
集合属性注入
<!--beam.xml-->
<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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="stu" class="top.pastors.Stu">
<!--注入数组类型属性-->
<property name="arrays">
<array>
<value>课程1</value>
<value>课程2</value>
</array>
</property>
<!--注入properties集合类型属性-->
<property name="properties">
<props>
<prop key="name">课程1</prop>
<prop key="value">6666</prop>
</props>
</property>
<!--注入List集合类型属性-->
<property name="list">
<list>
<value>zhangsan</value>
<value>lisi</value>
</list>
</property>
<!--注入Map集合类型属性-->
<property name="maps">
<map>
<entry key="name" value="值1"/>
<entry key="value" value="值2"/>
</map>
</property>
<!--注入Set集合类型属性-->
<property name="sets">
<set>
<value>值1</value>
<value>值2</value>
</set>
</property>
<!--注入对象类型属性-->
<property name="lists">
<list>
<ref bean="course1"></ref>
<ref bean="course2"></ref>
</list>
</property>
</bean>
<bean id="course1" class="top.pasotrs.Course">
<property name="cname" value="值1"></property>
</bean>
<bean id="course2" class="top.pasotrs.Course">
<property name="cname" value="值2"></property>
</bean>
</beans>
<!--提取复用代码-->
<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">
<util:list id="bookList">
<value>值1</value>
<value>值2</value>
<value>值3</value>
</util:list>
<bean id="book" class="top.pastors.Book">
<property name="list" ref="bookList"></property>
</bean>
</beans>
SpEL SpringEL
- 常量
- 引用bean
- 引用bean属性
- 引用bean方法
- beanld.methodName().method()
- 引用静态方法
- T(java.lang.Math).PI
- 运算符支持
- 正则表达式支持
- 集合支持
<a name="a4e227a3"></a>
#### Spring整合Mybatis
```xml
<!--spring整合mybatis后控制的创建连接用的对象-->
<bean class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="typeAliasesPackage" value="top.pastors.domain"/>
</bean>
<!--加载mybatis映射配置的扫描,将其作为spring的bean进行管理-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="top.pastors.dao"/>
</bean>
IOC注解
开启注解功能
- 无论是注解格式还是XML配置格式,最终都是将资源加载到IIOC容器中
- 从加载效率上来说注解要优于XML
<context:component-scan base-package="包名"/>
@Component
- 类型:类注解
- 作用:设置该类为spring管理的bean
- 属性:定义Bean的访问ID
- 说明:
- @Controller()、@Service()、@Repository() 都是@Componet衍生注解 功能一致
@Component("userService")
public class UserServiceImpl impements UserDao{}
@Scope
- 类型:类注解
- 作用:定义Bean作用域
- 属性:默认为:singleton(单例模式) 可选为:prototype(原型模式)
- 说明:
- 该类对应ben标签中的scope属性
@Scope
public class UserServiceImpl impements UserDao{}
@PostConstruct
- 类型:方法注解
- 作用:指定初始化方法
- 说明:
- 该类对应ben标签中的init-method属性
@PostConstruct
public void init(){}
@PreDestroy
- 类型:方法注解
- 作用:指定销毁方法
- 说明:
- 该类对应ben标签中的destroy-method属性
@PreDestroy
public void destroy(){}
@Bean
- 类型:方法注解
- 作用:设置该方法的返回值为spring管理的bean
- 属性:定义Bean的访问ID
- 说明:
- 因为第三方bean无法在其源码上修改,使用@Bean解决第三方bean的引入问题
- 该注解用于替换XML配置文件中的静态工程与实例工厂创建bean 不区分方法是否为静态或非静态
- @Bean所在的类必须被spring扫描加载,否则无法生效
@Value
- 类型:属性注解、方法注解
- 作用:设置对应属性的值
- 属性:定义对应的属性值或参数值
- 说明:
- value值仅支持费引用类型数据,赋值时对方法的所有参数全部赋值
- value值支持读取properties文件中的属性值,通过类属性将properties中数据传入类中
- value支持SpEL
- 如果添加在属性上方,可以省略set方法
@Value("${jdbc.username}")
private String username;
@Autowired、@Qualifier
- 类型:属性注解、方法注解
- 作用:(自动装配)设置对应属性的对象或对方法进行引用类型传参
- 属性:
- required:定义该属性是否允许为null
- 说明:
- @Autowired默认按类型装配,指定@Qualifier后可以指定自定装配的bean的id
- @Inject与@Named是JSR330规范中的注解,功能与@Autowired、@Qualifier完全相同,适用于不同架构场景
- @Resource是JSR250规范中的注解,可以简化书写格式
- name:设置注入的bean的id
- type:设置注入的bean的类型,接收的参数为Class类型
@Autowired(required = false)
@Qualifier("userDao")
private UserDao userDao;
@PropertySource
- 类型:类注解
- 作用:加载properties文件
- 属性:
- value:设置加载的properties文件名
- ignoreResourceNotFound:如果资源未找到,是否忽略,默认为false
- 说明:不支持 * 通配格式,一旦加载,所有的spirng控制的bean中均可使用对应属性值
@PropertySource(value = "classpath:1.properties")
public class Test{
@Value("${num}")
private int num;
}
@Configuration、@ComponentScan
- 类型:类注解
- 作用:(替换XML)设置当前类为spring核心配置加载类
- 说明:
- 核心配置类用于替换spring核心配置文件,此类可以设置空的,不设置变量与属性
- bean扫描工作使用注解@ComponentScan替代
@Configuration
@ComponentScan("包名")
public class Test{}
//Spring创建的对象换为
ApplicationContext ctx = new AnnotationConfigApplicationContext(Test.class);
@Configurable
- 类型:类注解
- 作用:用来自动注入bean的注解,不需要通过BeanFactory去获取
- 说明:
@Configurable
public class Test{}
@Import
- 类型:类注解
- 作用:导入第三方bean作为spring控制的资源
- 说明:
- 在同一类上,仅允许添加一次,如果需要导入多个,使用数组的形式进行设定
- 在被导入的类中可以继续使用@Import导入其他资源
- @Bean所在的类可以使用导入的形式进入spring容器,无需声明为bean
@Configurable
@Import(Test1.class)
public class Test{}
加载控制
@DependsOn
- 类型:类注解、方法注解
- 作用:控制Bean的加载顺序,使其在指定bean加载完毕后再加载
- 属性:设置当前bean所依赖bean的id
- 说明:
- 配置在方法上,优先于@Bean配置的bean进行加载
- 配置在类上,优先于当前类中所有@Bean配置的bean进行加载
- 配置在类上,优先于当@Component等配置的bean进行加载
@DependsOn(“beanId”)
public class Test{}
@Order
- 类型:配置类注解
- 作用:控制配置类的加载顺序
- 属性:从1开始(最先加载)
@Order(1)
public class Test{}
@Lazy
- 类型:类注解、方法注解
- 作用:控制bean的加载时机,使其延迟加载
@Order(1)
public class Test{}
AOP
1、AOP:Aspect Oriented Programming(面向切面编程),OOP是面向对象编程,AOP是在OOP基础之上的一种更高级的设计思想。
2、OOP和AOP之间也存在一些区别,OOP侧重于对象的提取和封装。——封装对象
AOP侧重于方面组件,方面组件可以理解成封装了通用功能的组件,方面组件可以通过配置方式,灵活地切入到某一批目标对象方法上。——封装功能
3、AOP用于处理系统中分布于各个模块的横切关注点,比如事务管理、日志、缓存等。
- 在实际开发中,比如商品查询、促销查询等业务,都需要记录日志、异常处理等操作,AOP把所有共用代码都剥离出来,单独放置到某个类中进行集中管理,在具体运行时,由容器进行动态织入这些公共代码。
- AOP主要一般应用于签名验签、参数校验、日志记录、事务控制、权限控制、性能统计、异常处理等。
AOP概念
- Joinpoint 连接点
- Pointcut 切入点
- Advice 通知
- 通知类型
- Aspect 切面
- Target 目标对象
- Weaving 织入
- Proxy 代理
- Introduction 引入/引介
- 开发阶段(开发者完成)
- 正常的制作程序
- 将非共性功能开发到对应的目标对象类中,并制作切入点方法
- 将共性功能独立开发出来,制作成通知
- 在配置文件中,声明切入点
- 在配置文件中,声明切入点与通知间的关系(含通知类型),即切面
- 运行阶段(AOP完成)
- Spring容器加载配置文件,监控所有配置的切入点方法的执行
- 当监控到切入点方法被运行,使用代理机制,动态创建目标对象的代理对象,根据通知类型,在代理对象的对应位置将通知对应的功能织入,完成完整代码逻辑并运行
AOP底层原理
- Spring AOP使用的是动态代理。
- 所谓的动态代理,就是说AOP框架不会去修改字节码,而是在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理, 并回调原对象的方法。
- Spring AOP中的动态代理,主要有两种方式:
- JDK动态代理和CGLIB动态代理。JDK动态代理通过“反射”来接收被代理的类,并且要求被代理的类必须实现一个接口。
- JDK动态代理的核心是InvocationHandler接口和Proxy类。如果目标类没有实现接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。
- CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态地生成某个类的子类。注意,CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。
AOP常用注解
AOPXML
AspectJ:Aspect切面在java中的实现
<!--引用AOP命名空间-->
<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
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--开启AOP命名空间-->
<bean id="userService" class="top.pastors.service.impl.UserServiceImpl"/>
<!--配置共性功能成供spring控制的资源-->
<bean id="myAdvice" class="top.pastors.aop.AOPadvice"/>
<!--开启AOP配置 可多个-->
<aop:config>
<!--配置公共切入点 可多个
-->
<aop:pointcut id="pt" expression="execution(* *..*(..))"/>
<!--配置具体AOP通知对应的切入点 可多个
ref:指定对应通知类Bean的ID
-->
<aop:aspect ref="myAdvice">
<!--前切入点
method:共性功能类中的方法
pointcut-ref:切入点id
-->
<aop:before method="function" pointcut-ref="pt"/>
<!--配置局部切入点 可多个
expression与pointcut 功能一致 直接使用切入点表达式
-->
<aop:before method="function" expression="execution(* *..*(..))"/>
<aop:before method="function" pointcut="execution(* *..*(..))"/>
</aop:aspect>
</aop:config>
</beans>
切入点表达式
- 切入点描述的是某个方法
- 切入点表达式是一个快速匹配方法描述的通配格式,类似于正则表达式
关键字 (访问修饰符 返回值 包名.类名.方法名(参数) 异常名)
- 关键字:描述表达式的匹配模式(参看关键字列表)
- 访问修饰符:方法的访问控制权限修饰符
- 类名:方法所在的类(此处可以配置接口名称)
- 异常:方法定义中指定抛出的异常
- 例如
execution (public User top.pastors.service.UserService.findById(int))
- execution:匹配执行指定方法
- args:匹配带有指定参数类型的方法
- within:
- this:
- target:
- @args:
- @within:
- @target:
- @annotation:
- bean:
- reference pointcut:
切入点表达式通配符
- *:单个独立的任意符号,可以独立出现,也可以作为前戳或者后戳的匹配符出现
execution (public * top.pastors.*.UserService.find*(*))
- 匹配top.pastors包下的任意包中的UserService类或接口中所有find开头的带有一个参数的方法
- ..:多个联系的任意字符,可以独立出现,常用于简化包名与参数的书写
execution (public User top..UserService.findById(..))
- 匹配top包下的任意包中的UserService类或接口中所有名称为findById带有任意个参数的方法
- +:专用于匹配子类类型
execution (* *..*Service+.*(..))
切入点表达式逻辑运算符
- &&:(并且)连接两个切入点表达式,表示两个切入点表达式同时成立的匹配
- ||:(或者)连接两个切入点表达式,表示两个切入点表达式成立任意一个匹配
- !:(非)连接两个切入点表达式,表示该切入点表达式不成立的匹配
切入点表达式范例
//任意方法拦截
execution(* *(..))
//任意方法拦截
execution(* *..*(..))
//任意方法拦截
execution(* *..*.*(..))
//public 任意方法拦截
execution(public * *..*.*(..))
//public 返回值为int 任意方法拦截
execution(public int *..*.*(..))
//public 返回值为void 任意方法拦截
execution(public void *..*.*(..))
//public 返回值为void top包下的任意方法拦截
execution(public void top..*.*(..))
//public 返回值为void top包下的任意包下的service包下的类或接口拦截
execution(public void top..service.*.*(..))
//public 返回值为void top包下的pastors包下的service包下的类或接口拦截
execution(public void top.pastors.service.*.*(..))
//public 返回值为void top包下的pastors包下的service包下的以User开头的类或接口的任意方法拦截
execution(public void top.pastors.service.User*.*(..))
//public 返回值为void top包下的pastors包下的service包下的以Service结尾的类或接口的任意方法拦截
execution(public void top.pastors.service.*Service.*(..))
//public 返回值为void top包下的pastors包下的service包下的UserService类或接口的任意方法拦截
execution(public void top.pastors.service.UserService.*(..))
//public 返回值为void top包下的pastors包下的service包下的UserService类或接口的find开头的方法拦截
execution(public User top.pastors.service.UserService.find*(..))
//public 返回值为void top包下的pastors包下的service包下的UserService类或接口的Id结尾的方法拦截
execution(public User top.pastors.service.UserService.*Id(..))
//public 返回值为void top包下的pastors包下的service包下的UserService类或接口的findById的方法拦截
execution(public User top.pastors.service.UserService.findById(..))
//public 返回值为void top包下的pastors包下的service包下的UserService类或接口的findById下的带有1个int参数的方法拦截
execution(public User top.pastors.service.UserService.findById(int))
//public 返回值为void top包下的pastors包下的service包下的UserService类或接口的findById下的带有2个int参数的方法拦截
execution(public User top.pastors.service.UserService.findById(int,int))
//public 返回值为void top包下的pastors包下的service包下的UserService类或接口的findById下的带有1个int参数,1个任意参数的方法拦截
execution(public User top.pastors.service.UserService.findById(int,*))
//public 返回值为void top包下的pastors包下的service包下的UserService类或接口的findById下的带有1个任意参数,1个int参数的方法拦截
execution(public User top.pastors.service.UserService.findById(*,int))
//public 返回值为void top包下的pastors包下的service包下的UserService类或接口的findById下的无参数的方法拦截
execution(public User top.pastors.service.UserService.findById())
//public 返回值为void top包下的pastors包下的service包下的所有Service结尾的类或者接口的子类或实现类中的findAll不限参数的方法拦截
execution(List top.pastors.service.*Service+.findAll(..))
切入点配置经验
- 企业开发命名规范严格遵循规范文档进行
- 先为方法配置局部切入点
- 再抽取类中公共切入点
- 最后抽取全局切入点
- 代码走查过程中检测切入点是否存在越界性包含
- 代码走查过程中检测切入点是否存在非包含性进驻
- 设定AOP执行检测程序,在单元测试中监控通知被执行次数与预计次数是否匹配
- 设定完毕的切入点如果发生调整务必进行回归测试
(以上规则适用于XML配置格式)
Spring事务
Spring事务核心对象
- PlatfromTransactionManager:平台事务管理器
- DataSourceTransactionManager:适用于Spring JDBC或MyBatis
- HibernateTransactionManager:适用于Hibernate3.0及以上版本
- JpaTransactionManager:适用于JPA
- JdoTransactionManager:适用于JDO
- JtaTransactionManager:适用于JTA
- TransactionDefinition
- TransactionStatus
//获取事务
TransactionStatus getTransaction(TransactionDefinition definition);
//提交事务
void commit(TransactionStatus status);
//回滚事务
void rollback(TransactionStatus status);