Spring 提供了自动代理机制, 可以让容器自动生成代理, 从而把开发人员从繁琐的配置中解脱出来 . 具体是使用 BeanPostProcessor 来实现这项功能.
这三种自动代理创建器 为: BeanNameAutoProxyCreator , DefaultAdvisorAutoProxyCreator , AbstractAdvisorAutoProxyCreator.
1BeanPostProcessor
BeanPostProcessor 代理创建器的实现类可以分为 3 类:
类型 | 实现类 |
---|---|
基于 Bean 配置名规则 | BeanNameAutoProxyCreator |
基于 Advisor 匹配规则 | DefaultAdvisorAutoProxyCreator |
基于 Bean 中的 AspectJ 注解标签的匹配规则 | AnnotationAwareAspectJAutoProxyCreator |
BeanPostProcessor 类继承关系
所有的自动代理器类都实现了 BeanPostPorcessor , 在容器实例化 Bean 时, BeanPostProcessor 将对它进行加工处理, 所以自动代理创建器能够对满足匹配规则的 bean 自动创建代理对象.
2 BeanNameAutoProxyCreator
假设有以下两个实体类 (用户与充电宝).
用户类:
- public class User {
- public void rent(String userId) {
- System.out.println("User: 租赁 [充电宝]");
- }
- public void back(String userId){
- System.out.println("User: 归还 [充电宝]");
- }
- }
充电宝:
- public class Charger {
- public void rent(String userId) {
- System.out.println("Charger:[充电宝] 被租赁");
- }
- }
我们希望通过 BeanNameAutoProxyCreator 通过 Bean 的名称来自动创建代理, 实现增强:
- <?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"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
- <bean id="user" class="net.deniro.spring4.aop.User"/>
- <bean id="charger" class="net.deniro.spring4.aop.Charger"/>
- <!-- 前置增强 -->
- <bean id="rentBeforeAdvice" class="net.deniro.spring4.aop.RentBeforeAdvice"/>
- <!-- 使用 BeanNameAutoProxyCreator-->
- <bean
- class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"
- p:beanNames="*er"
- p:interceptorNames="rentBeforeAdvice"
- p:optimize="true"
- ></bean>
- </beans>
BeanNameAutoProxyCreator 的 beanNames 属性允许指定一组需要自动代理的 Bean 名称, 这里可以使用 * 通配符 .
因为我们需要代理的类名分别是 user 与 charger, 都是以 er 结尾的, 所以我们这里定义为 *er.
也可以通过 beanNames 的 value 值来明确指定需要代理的 Bean 名称, 多个以逗号分隔 (更常用).
- <!-- 指定自动代理的 Bean 名称 -->
- <property name="beanNames" value="user,charger">
- </property>
也可以通过 list 方式来指定 beanNames 的值:
- <property name="beanNames">
- <list>
- <value>user</value>
- <value>charger</value>
- </list>
- </property>
p:optimize 设置为 true, 则表示使用 CGLib 动态代理技术.
通过这样的配置之后, 容器在创建 user 和 charger Bean 的实例时, 就会自动为它们创建代理对象, 而这一操作对于使用者来说完全是透明的 .
单元测试:
- User user = (User) context.getBean("user");
- Charger charger = (Charger) context.getBean("charger");
- String userId = "001";
- user.rent(userId);
- charger.rent(userId);
输出结果:
准备租赁的用户 ID:001
User: 租赁 [充电宝]
准备租赁的用户 ID:001
Charger:[充电宝] 被租赁
3 DefaultAdvisorAutoProxyCreator
切面 Advisor 是切点和增强的复合体, 而 DefaultAdvisorAutoProxyCreator 能够扫描 Advisor, 并将 Advisor 自动织入到匹配的目标 Bean 中.
- <bean id="user" class="net.deniro.spring4.aop.User"/>
- <bean id="charger" class="net.deniro.spring4.aop.Charger"/>
- <!-- 前置增强 -->
- <bean id="rentBeforeAdvice" class="net.deniro.spring4.aop.RentBeforeAdvice"/>
- <!-- 静态正则表达式方法名匹配 -->
- <bean id="regexpAdvisor"
- class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"
- p:advice-ref="rentBeforeAdvice">
- <!-- 匹配模式 -->
- <property name="patterns">
- <list>
- <!-- 匹配字符串 -->
- <value>.*rent.*</value>
- </list>
- </property>
- </bean>
- <!-- 使用 DefaultAdvisorAutoProxyCreator-->
- <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
首先我们配置了以静态正则表达式方法名匹配的切面, 然后直接配置了 DefaultAdvisorAutoProxyCreator Bean.
测试代码与输出结果与上一小节的 BeanNameAutoProxyCreator 相同.
JDK 动态代理是通过接口来实现方法拦截, 所以必须确保要拦截的目标在接口中有定义.
CGLib 动态代理是通过动态生成代理子类来实现方法拦截, 所以必须确保要拦截的目标方法可以被子类所访问, 也就是目标方法必须定义为非 final, 且非私有实例方法 .
来源: http://www.bubuko.com/infodetail-2977859.html