zoukankan      html  css  js  c++  java
  • Java Spring-传统AOP开发

    2017-11-10 17:25:48

    Spring中通知Advice类型(增强代码):

    • 前置通知,org.springframework.aop.MethodBeforeAdvice:方法前
    • 后置通知,org.springframework.aop.AfterReturningAdvice:方法后
    • 环绕通知,org.aopalliance.intercept.MethodInterceptor:方法前后
    • 异常抛出通知,org.springframework.aop.ThrowsAdvice:异常抛出后的增强
    • 引介通知,org.springframework.aop.IntroductionInterceptor:类的增强

    Spring中切面的类型:

    • Advisor:AOP中的传统切面,Advice本身就是一个切面,对所有方法进行增强 -- 也被称为不带切点的切面
    • PointcutAdvisor:针对某些方法进行增强 -- 也被称为带有切点的切面
    • IntroductionAdvisor:代表引介的切面,针对类的切面

    Spring中AOP开发的几个步骤:

    • 第一步:导入相应jar包.
      * spring-aop-3.2.0.RELEASE.jar
      * com.springsource.org.aopalliance-1.0.0.jar
    • 第二步:编写被代理对象
    • 第三步:编写增强的代码,编写具体类来实现前置增强,后置增强以及环绕增强
    • 第四步:配置生成代理

     一、不带切点的切面:Advisor

    // 接口
    public interface Person {
        public void add();
        public void delete();
    }
    
    // 实现类
    public class PersonImpl implements Person {
        @Override
        public void add() {
            System.out.println("添加方法...");
        }
    
        @Override
        public void delete() {
            System.out.println("删除方法...");
        }
    }
    
    // 测试
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:spring-config.xml")
    public class Demo {
        @Resource(name = "proxy")
        private Person p;
    
        @Test
        public void fun(){
            p.add();
        }
    }
    

    通过xml进行配置代理:

    生成代理Spring基于ProxyFactoryBean类,底层自动选择使用JDK的动态代理还是CGLIB的代理.
    属性:

    • target : 代理的目标对象
    • proxyInterfaces : 代理要实现的接口

      如果多个接口可以使用以下格式赋值

    <list>
    <value></value>
    ....
    </list>

    • proxyTargetClass : 是否对类代理而不是接口,设置为true时,使用CGLib代理
    • interceptorNames : 需要织入目标的Advice
    • singleton : 返回代理是否为单实例,默认为单例
    • optimize : 当设置为true时,强制使用CGLib
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns="http://www.springframework.org/schema/beans"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <!--定义目标对象-->
        <bean id="person" class="spring1.PersonImpl"/>
        <!--定义增强-->
        <bean id="before" class="spring1.MethodBef"/>
    
        <!--Spring支持配置生成代理-->
        <bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
            <!-- 设置目标对象 -->
            <property name="target" ref="person"/>
            <!-- 设置实现的接口 ,value中写接口的全路径 -->
            <property name="proxyInterfaces" value="spring1.Person"/>
            <!-- 需要使用的切面,这里增强即是切面-->
            <property name="interceptorNames" value="before"/>
        </bean>
    </beans>
    

    注意:

    • 使用注解的时候不仅需要导入Junit4.12,还需要导入hamcrest-core
    • 在使用接口方式生成代理的时候,返回的类的类型必须是接口类型。
    • 这种方法有两个弊端,一是每个类都需要手动进行代理的配置,显得比较麻烦;二是由于是不带切点的,导致灵活性变差,所以并不常用。

    二、带有切点的切面:PointcutAdvisor

    PointcutAdvisor接口有三种实现:DefaultPointcutAdvisor , RegexpMethodPointcutAdvisor 和 NameMatchMethodPointcutAdvisor,它们都在org.springframework.aop.support包中。

    • RegexpMethodPointcutAdvisor是通过正则表达式来匹配拦截的方法
    • NameMatchMethodPointcutAdvisor通过直接指定那些方法是需要拦截的,它也可以用*作为通配符
    • DefaultPointcutAdvisor则需要自定义切入点类
    // 具体类
    public class PersonImpl implements Person {
        @Override
        public void add() {
            System.out.println("添加方法...");
        }
    
        @Override
        public void delete() {
            System.out.println("删除方法...");
        }
    }
    
    // 自定义增强
    import org.aopalliance.intercept.MethodInterceptor;
    import org.aopalliance.intercept.MethodInvocation;
    
    public class AroundAdvice implements MethodInterceptor {
        @Override
        public Object invoke(MethodInvocation methodInvocation) throws Throwable {
            System.out.println("环绕前增强...");
    
            // 执行目标对象的方法
            Object res = methodInvocation.proceed();
    
            System.out.println("环绕后增强...");
    
            return res;
        }
    }
    
    
    // 测试
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    import javax.annotation.Resource;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:spring-config.xml")
    public class Demo {
        @Resource(name = "proxy2")
        private Person p;
    
        @Test
        public void fun(){
            p.add();
        }
    }
    

    通过配置来生成代理:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns="http://www.springframework.org/schema/beans"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <!--定义目标对象-->
        <bean id="person" class="spring1.PersonImpl"/>
        <!--定义增强-->
        <bean id="before" class="spring1.MethodBef"/>
        <bean id="around" class="spring1.AroundAdvice"/>
    
    
        <!--Spring支持配置生成代理-->
        <bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
            <!-- 设置目标对象 -->
            <property name="target" ref="person"/>
            <!-- 设置实现的接口 ,value中写接口的全路径 -->
            <property name="proxyInterfaces" value="spring1.Person"/>
            <!-- 需要使用的增强 -->
            <property name="interceptorNames" value="before"/>
        </bean>
    
        <!--定义带有切点的切面代理-->
    
        <!--定义切点切面-->
        <bean id="mypointcut" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
            <!--定义正则表达式,来限定切点-->
            <property name="pattern" value=".*"/>
            <!--添加增强-->
            <property name="advice" ref="around"/>
        </bean>
    
        <bean id="proxy2" class="org.springframework.aop.framework.ProxyFactoryBean">
            <!-- 设置目标对象 -->
            <property name="target" ref="person"/>
            <!-- 设置实现的接口 ,value中写接口的全路径 -->
            <property name="proxyInterfaces" value="spring1.Person"/>
            <!-- 需要使用的增强 -->
            <property name="interceptorNames" value="mypointcut"/>
        </bean>
    </beans>
    

    三、自动代理

    前面的案例中,每个代理都是通过ProxyFactoryBean织入切面代理,在实际开发中,非常多的Bean每个都配置ProxyFactoryBean开发维护量巨大。

    自动创建代理(基于后处理Bean,在Bean创建的过程中完成的增强,生成Bean就是代理 .)

    • BeanNameAutoProxyCreator :根据Bean名称创建代理
    • DefaultAdvisorAutoProxyCreator :根据Advisor本身包含信息创建代理
    • AnnotationAwareAspectJAutoProxyCreator :基于Bean中的AspectJ 注解进行自动代理

    基于后处理Bean的都不用配置id。

    * BeanNameAutoProxyCreator: 按名称生成代理

    // 实现类
    public class PersonImpl implements Person {
        @Override
        public void add() {
            System.out.println("添加方法...");
        }
    
        @Override
        public void delete() {
            System.out.println("删除方法...");
        }
    }
    
    //增强
    import org.aopalliance.intercept.MethodInterceptor;
    import org.aopalliance.intercept.MethodInvocation;
    
    public class AroundAdvice implements MethodInterceptor {
        @Override
        public Object invoke(MethodInvocation methodInvocation) throws Throwable {
            System.out.println("环绕前增强...");
    
            // 执行目标对象的方法
            Object res = methodInvocation.proceed();
    
            System.out.println("环绕后增强...");
    
            return res;
        }
    }
    
    public class MethodBef implements MethodBeforeAdvice{
        /**
         * method:执行的方法
         * args:参数
         * o:目标对象
        */
        @Override
        public void before(Method method, Object[] objects, Object o) throws Throwable {
            System.out.println("前置增强...");
        }
    }
    
    // 测试
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    import javax.annotation.Resource;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:config.xml")
    public class Demo {
        // 这里直接使用person进行注入就可以了
        @Resource(name = "person")
        private Person p;
    
        @Test
        public void fun(){
            p.add();
        }
    }
    

    使用XML进行配置(如果想对特定方法,只需要配置一个有切点的切面就可以了):

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns="http://www.springframework.org/schema/beans"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <!--定义目标对象-->
        <bean id="person" class="spring1.PersonImpl"/>
        <!--定义增强-->
        <bean id="before" class="spring1.MethodBef"/>
        <bean id="around" class="spring1.AroundAdvice"/>
    
        <!--  自动代理:按名称的代理,基于后处理Bean,后处理Bean,不需要配置id-->
        <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
            <!--设置需要代理的beanname,支持正则-->
            <property name="beanNames" value="person"/>
            <property name="interceptorNames" value="around"/>
        </bean>
    
    </beans>
    

    * DefaultAdvisorAutoProxyCreator:根据切面中定义的信息生成代理

    // 实现类
    public class PersonImpl implements Person {
        @Override
        public void add() {
            System.out.println("添加方法...");
        }
    
        @Override
        public void delete() {
            System.out.println("删除方法...");
        }
    }
    
    // 增强
    public class AroundAdvice implements MethodInterceptor {
        @Override
        public Object invoke(MethodInvocation methodInvocation) throws Throwable {
            System.out.println("环绕前增强...");
    
            // 执行目标对象的方法
            Object res = methodInvocation.proceed();
    
            System.out.println("环绕后增强...");
    
            return res;
        }
    }
    
    // 测试
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    import javax.annotation.Resource;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:config2.xml")
    public class Demo {
        // 这里直接使用person进行注入就可以了
        @Resource(name = "person")
        private Person p;
    
        @Test
        public void fun(){
            p.add();
            p.delete();
        }
    }
    

    使用配置进行自动代理:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns="http://www.springframework.org/schema/beans"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <!--定义目标对象-->
        <bean id="person" class="spring1.PersonImpl"/>
        <!--定义增强-->
        <bean id="before" class="spring1.MethodBef"/>
        <bean id="around" class="spring1.AroundAdvice"/>
    
        <!--  定义一个带有切点的切面 -->
        <bean id="myPointcutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
            <property name="pattern" value=".*add.*"/>
            <property name="advice" ref="around"/>
        </bean>
        <!--  自动生成代理 -->
        <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean>
    </beans>
    
  • 相关阅读:
    C#委托
    资源推荐 五个常用MySQL图形化管理工具
    C#数组
    虚方法与多态
    How to connect to MySQL database from Visual Studio VS2010 – problems with NET connectors
    2021秋软工实践第二次结对编程作业
    2021秋软工实践第一次个人编程作业
    低维数据可视化
    2021秋季软件工程实践总结
    2021秋软工实践第一次结对编程作业
  • 原文地址:https://www.cnblogs.com/hyserendipity/p/7816070.html
Copyright © 2011-2022 走看看