Spring AOP (五)
Spring AOP (五)
前面我们学习了ProxyFactoryBean,给我们带来了很大的方便尽管我们在上面进行了一些优化,但是我们还是需要编写一些有用规律的配置文件,而AutoProxy正是一种可以自动代理对象的技术,今天我们就来具体学习一下。
AutoProxy
AutoProxy的存在有非常重要的现实意义,在团队的合作和分工中,架构师应对项目整体结构考虑,例如log服务,而对于一般程序猿来说,首要关注的是业务逻辑,这时候AutoProxy就给我们提供了一些帮助,AutoProxy由AutoProxyCreator来完成。
Spring提供了两种AutoProxyCreator
- BeanNameAutoProxyCreator
- DefaultAdvisorAutoProxyCreator
BeanNameAutoProxyCreator
正如其命名,BeanNameAutoProxyCreator可以让我们通过Bean的名称来将同一个advice或Advisor自动应用到这些Bean。我们可以通过通配符来指定这些Bean的名称,之后的工作全部由BeanNameAutoProxyCreator和ApplicationContext来完成。这样我们甚至不需要去配置任何ProxyFactoryBean就可以实现对指定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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 定义前置通知Bean -->
<bean id="advice" class="boy.aop.advice.BeforeMethod"></bean>
<!-- 定义正则匹配默认的切入点 -->
<bean id="advisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="advice" ref="advice"></property>
<property name="pointcut">
<bean class="org.springframework.aop.support.JdkRegexpMethodPointcut">
<property name="pattern">
<value>.*get.*</value>
</property>
</bean>
</property>
</bean>
<bean id="proxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<value>p*</value>
<value>message</value>
</list>
</property>
<property name="interceptorNames">
<list>
<value>advisor</value>
</list>
</property>
</bean>
<bean id="pointcutMethod" class="boy.aop.pointcut.PointcutMethod">
<property name="age" value="21"></property>
<property name="name" value="kk"></property>
<property name="title" value="kk love mm"></property>
</bean>
<bean id="message" class="boy.aop.pointcut.AutoLove">
<property name="kk" value="kk love mm"></property>
<property name="mm" value="mm love kk"></property>
</bean>
</beans>
BeanNameAutoProxyTest类
package boy.aop.pointcut;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
/**
* Created by Boy on 2016/12/15 22:42.
*/
public class BeanNameAutoProxyTest {
public static void main(String[] args){
ApplicationContext ctx = new FileSystemXmlApplicationContext("/src/main/resources/SpringAutoProxy.xml");
PointcutMethod pm = (PointcutMethod) ctx.getBean("pointcutMethod");
AutoLove al = (AutoLove) ctx.getBean("message");
pm.getTitle();
pm.getName();
pm.getAge();
al.getKk();
al.getMm();
}
}
运行结果
22:47:47.297 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Finished creating instance of bean 'message'
22:47:47.299 [main] DEBUG org.springframework.context.support.FileSystemXmlApplicationContext - Unable to locate LifecycleProcessor with name 'lifecycleProcessor': using default [org.springframework.context.support.DefaultLifecycleProcessor@3ec300f1]
22:47:47.300 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'lifecycleProcessor'
22:47:47.303 [main] DEBUG org.springframework.core.env.PropertySourcesPropertyResolver - Could not find key 'spring.liveBeansView.mbeanDomain' in any property source
22:47:47.305 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'pointcutMethod'
22:47:47.305 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'message'
BeforeMethod : now we start before!
我们处理 getName 方法
BeforeMethod : now we start before!
我们处理 getName 方法
BeforeMethod : now we start before!
我们处理 getAge 方法
BeforeMethod : now we start before!
我们处理 getKk 方法
BeforeMethod : now we start before!
我们处理 getMm 方法
前面我们使用的是ProxyFactoryBean,而这里我们使用BeanNameAutoProxyCreator自动为指定的BeanName进行代理。BeanNameAutoProxyCreator是最基本的AutoProxyCreator表现形式,另一种就是DefaultAdvisorAutoProxyCreator。
DefaultAdvisorAutoProxyCreator
DefaultAdvisorAutoProxyCreator是一种比较复杂的AutoProxyCreator,它的功能更加强大,从形式看,它更加的简洁,可以自动搜索ApplicationContext中的Advisor,然后根据Advisor中的Pointcut来决定是否将advice应用到ApplicationContext中的任意Bean的任意方法。BeanNameAutoProxyCreator需要指定Bean的名称,然后在根据Advisor中的Pointcut来决定是否应用advice,而DefaultAdvisorAutoProxyCreator直接使用Advisor中的Pointcut去匹配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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="proxyCreator"
class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
<bean id="advice" class="boy.aop.advice.BeforeMethod"></bean>
<bean id="advisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="advice" ref="advice"></property>
<property name="pointcut">
<bean class="org.springframework.aop.support.JdkRegexpMethodPointcut">
<property name="pattern" value=".*get.*"></property>
</bean>
</property>
</bean>
<bean id="pointcutMethod" class="boy.aop.pointcut.PointcutMethod">
<property name="age" value="21"></property>
<property name="name" value="kk"></property>
<property name="title" value="kk love mm"></property>
</bean>
<bean id="autoLove" class="boy.aop.pointcut.AutoLove">
<property name="kk" value="kk love mm"></property>
<property name="mm" value="mm love kk"></property>
</bean>
</beans>
DefaultAdvisorAutoProxyCreatorTest类
package boy.aop.pointcut;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
/**
* Created by Boy on 2016/12/15 23:10.
*/
public class DefaultAdvisorAutoProxyCreatorTest {
public static void main(String[] args){
ApplicationContext ctx = new FileSystemXmlApplicationContext("src/main//resources/SpringDefaultAutoProxy.xml");
PointcutMethod pm1 = (PointcutMethod) ctx.getBean("pointcutMethod");
AutoLove al1 = (AutoLove) ctx.getBean("autoLove");
pm1.getAge();
pm1.getName();
pm1.getTitle();
al1.getKk();
al1.getMm();
}
}
运行结果
23:13:15.870 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Finished creating instance of bean 'autoLove'
23:13:15.881 [main] DEBUG org.springframework.context.support.FileSystemXmlApplicationContext - Unable to locate LifecycleProcessor with name 'lifecycleProcessor': using default [org.springframework.context.support.DefaultLifecycleProcessor@40e6dfe1]
23:13:15.882 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'lifecycleProcessor'
23:13:15.883 [main] DEBUG org.springframework.core.env.PropertySourcesPropertyResolver - Could not find key 'spring.liveBeansView.mbeanDomain' in any property source
23:13:15.885 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'pointcutMethod'
23:13:15.885 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'autoLove'
BeforeMethod : now we start before!
我们处理 getAge 方法
BeforeMethod : now we start before!
我们处理 getName 方法
BeforeMethod : now we start before!
我们处理 getName 方法
BeforeMethod : now we start before!
我们处理 getKk 方法
BeforeMethod : now we start before!
我们处理 getMm 方法
可以看到,我们的配置文件更精简了,但是我们不能一味的使用简单的形式,每一种代理方式都有它的特别之处。BeanNameAutoProxyCreator的interceptorNames属性既可以指定advice,也可以指定Advisor,但是在DefaultAdvisorAutoProxyCreator中,因为我们需要Advisor中的Pointcut,所以Advisor是必需的。