Spring 提供了自动代理机制,可让容器自动生成代理,从而把开发人员从繁琐的配置中解脱出来 。 具体是使用 BeanPostProcessor 来实现这项功能。正则表达式
这三种自动代理建立器 为:BeanNameAutoProxyCreator , DefaultAdvisorAutoProxyCreator , AbstractAdvisorAutoProxyCreator。spring
BeanPostProcessor 代理建立器的实现类能够分为 3 类:单元测试
类型 | 实现类 |
---|---|
基于 Bean 配置名规则 | BeanNameAutoProxyCreator |
基于 Advisor 匹配规则 | DefaultAdvisorAutoProxyCreator |
基于 Bean 中的 AspectJ 注解标签的匹配规则 | AnnotationAwareAspectJAutoProxyCreator |
BeanPostProcessor 类继承关系测试
全部的自动代理器类都实现了 BeanPostPorcessor ,在容器实例化 Bean 时, BeanPostProcessor 将对它进行加工处理,因此自动代理建立器可以对知足匹配规则的 bean 自动建立代理对象。spa
假设有如下两个实体类(用户与充电宝)。代理
用户类:code
public class User { public void rent(String userId) { System.out.println("User:租赁【充电宝】"); } public void back(String userId){ System.out.println("User:归还【充电宝】"); } }
充电宝:regexp
public class Charger { public void rent(String userId) { System.out.println("Charger:【充电宝】被租赁"); } }
咱们但愿经过 BeanNameAutoProxyCreator 经过 Bean 的名称来自动建立代理,实现加强: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" 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:【充电宝】被租赁
切面 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, 且非私有实例方法 。