zoukankan      html  css  js  c++  java
  • spring8——AOP之Bean的自动代理生成器

      对于上篇博客http://www.cnblogs.com/cdf-opensource-007/p/6464237.html结尾处提到的两个问题,可以使用spring提供的自动代理生成器解决。自动代理生成器可以让我们把切面织入目标对象方法时不用再使用ProxyFactoryBean这个类来生成代理对象了,同时可以把切面织入多个代理代理对象,并且在获取代理对象时使用的是目标对象的id来获取,这符合正常的使用习惯。

      spring提供了两个自动代理生成器,一个是DefaultAdvisorAutoProxyCreator,这一款代理生成器比较暴力,会把容器内所有的切面向所有的目标对象织入,而且切面只能是顾问的形式。另一款自动代理生成器是BeanNameAutoProxyCreator,这一款代码生成器就比较友好了,可以让我们有选择性的对目标对象和切面进行织入的操作,而且切面可以是顾问或者通知的形式。

    下面我们还是以实验的形式说明问题。分别提供两个接口,和两个实现类,用于目标对象的创建,在上篇博客实验的基础上我们增加一个比较器的接口和实现类。

    计算器接口:

    public interface ICalculatorService {
        
        int add(int a,int b);
        
        int division(int a ,int b); 
    
    }

    比较器接口:

    public interface IComparatorService {
        
        void comparator(int a,int b);
    }

    计算器实现类:

    public class CalculatorServiceImpl implements ICalculatorService {
    
        @Override
        public int add(int a, int b) {
            return a+b;
        }
    
        @Override
        public int division(int a, int b) {
            return a/b;
        }
    
    }

    比较器实现类:

    public class ComparatorServiceImpl implements IComparatorService {
    
        @Override
        public void comparator(int a, int b) {
            
            if(a > b){
                System.out.println(a+"比"+b+"大");
            }else if(a < b){
                System.out.println(a+"比"+b+"小");
            }else{
                System.out.println(a+"等于"+b);
            }
    
        }
    
    }

    依旧提供三个切面的实现类,分别是前置通知,环绕通知和后置通知。

    public class TestMethodBeforeAdive implements MethodBeforeAdvice {
    
        @Override
        public void before(Method method, Object[] args, Object target) throws Throwable {
            System.out.println("执行前置通知--->"+"正在执行的方法名为"+method.getName());
        }
    
    }
    public class TestMethodInterceptor implements MethodInterceptor {
    
        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
            
            System.out.println("执行环绕通知--->"+"正在执行的方法名为"+invocation.getMethod().getName());
            
            Object[] arguments = invocation.getArguments();
            int a = (int)arguments[0];
            int b = (int)arguments[1];
            if(b == 0){
                System.err.println("除数不能为0");
                return -1;
            }
            if(a == 0){
                return 0;
            }
            
            
            return invocation.proceed();
        }
    
    }
    public class TesAfterRunningAdive implements AfterReturningAdvice {
    
        @Override
        public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
            
            System.out.println("执行后置通知--->"+"正在执行的方法名为"+method.getName());
        }
    
    }

    配置文件:

    <?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"
        xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
        xmlns:task="http://www.springframework.org/schema/task" xmlns:mvc="http://www.springframework.org/schema/mvc"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
                        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
                        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
                        http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd
                        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
            
        <!-- 目标对象 -->            
        <bean id="comparatorServiceTarget" class="com.opensource.service.impl.ComparatorServiceImpl"/>
        <bean id="calculatorServiceTarget" class="com.opensource.service.impl.CalculatorServiceImpl"/>
        <!-- 通知 -->
        <bean id="methodBeforeAdive" class="com.opensource.service.impl.TestMethodBeforeAdive"/>
        <bean id="afterRunningAdive" class="com.opensource.service.impl.TesAfterRunningAdive"/>
        <bean id="methodInterceptor" class="com.opensource.service.impl.TestMethodInterceptor"/>
        <!-- 顾问 -->
        <bean id="advisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
            <property name="advice" ref="methodInterceptor"/>
            <property name="mappedNames" value="division"/>
        </bean>
        <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
            <property name="beanNames">
                <list>
                    <value>calculatorServiceTarget</value>
                    <value>comparatorServiceTarget</value>
                </list>
            </property>
            <property name="interceptorNames">
                <list>
                    <value>methodBeforeAdive</value>
                    <value>afterRunningAdive</value>
                    <value>advisor</value>
                </list>
            </property>
        </bean>
        
        
        
        
    </beans>

    测试类:

    public class MyTest {
        public static void main(String[] args) {
            
            ApplicationContext ac = new ClassPathXmlApplicationContext("spring-bean.xml");
            ICalculatorService bean = (ICalculatorService)ac.getBean("calculatorServiceTarget");
            IComparatorService bean1 = (IComparatorService)ac.getBean("comparatorServiceTarget");
            int division = bean.division(10, 0);
            System.out.println("两数相除商为:"+division);
            System.err.println("---------------------------------------------------------");
            int add = bean.add(0, 2);
            System.out.println("两数想加和为:"+add);
            System.err.println("---------------------------------------------------------");
            bean1.comparator(0, 1);
            
            
            
        }
    
    
    }

    实验结果:

    这里提一句:对于BeanNameAutoProxyCreatorbeanNamesinterceptorNames这两个属性可以采用模糊匹配的方式,例如以下这种形式:

    <property name="beanNames" value="*Target"/>

    还有对顾问包装通知时,一个顾问只能包装一个通知,这也体现了顾问对于通知的精细化管理。

      最后说一点,我们作为程序员,研究问题还是要仔细深入一点的。当你对原理了解的有够透彻,开发起来也就得心应手了,很多开发中的问题和疑惑也就迎刃而解了,而且在面对其他问题的时候也可做到触类旁通。当然在开发中没有太多的时间让你去研究原理,开发中要以实现功能为前提,可等项目上线的后,你有大把的时间或者空余的时间,你大可去刨根问底,深入的去研究一项技术,为觉得这对一名程序员的成长是很重要的事情。

  • 相关阅读:
    第五周作业
    画图实例:一个计算机商店的基于Wed的订单处理系统的DFD图和ER图
    为什么要进行需求分析?通常对软件系统有哪些需求?
    面向过程(或者叫结构化)分析方法与面向对象分析方法到底区别在哪里
    几大开发模式的区别与联系
    说说我的困惑
    Python单元测试——深入理解unittest
    Devexpress 自定义下拉列表
    Devexpress TextEdit设置文本只能输入数字
    jetbain软件授权码
  • 原文地址:https://www.cnblogs.com/cdf-opensource-007/p/6476733.html
Copyright © 2011-2022 走看看