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是必需的。

这些天学习了AOP的基础,这些都属于Spring的基础部分,基础和原理很重要,每天进步一点点,共勉!!!

最后由 不一样的少年 编辑于2016年12月16日 23:11