• Spring AOP


    静态代理与动态代理:

    代理模式的定义是:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

    代理设计模式可以在不改变原始代码

    静态代理的实现:

     ISendBook接口

    public interface ISendBook {
        public void sendBook();
    }

     DangDang类,继承ISendBook接口:

    public class DangDang implements ISendBook{
    
        @Override
        public void sendBook() {
            // TODO Auto-generated method stub
            System.out.println("当当网-书籍部门,将书送到指定地址的客户手中");
        }
    }

     SFSendBookProxy类,继承ISendBook的另外一个接口

    public class SFSendBookProxy implements ISendBook{
        
        public ISendBook sendBook;
        
        public SFSendBookProxy(ISendBook sendBook){
            super();
            this.sendBook = sendBook;
        }
        
        @Override
        public void sendBook() {
            // TODO Auto-generated method stub
            System.out.println("顺丰接收书籍");
            sendBook.sendBook();
            System.out.println("顺丰书籍已送达");
        }
    }

     AopTest类

    public class AopTest {
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            ISendBook sendBook = new SFSendBookProxy(new DangDang());
            sendBook.sendBook();
        }
    }

     运行结果:

    顺丰接收书籍
    当当网-书籍部门,将书送到指定地址的客户手中
    顺丰书籍已送达

     上述代码实现了静态的代理,在改变原有的DangDang类的同时,对其方法进行了增加内容/功能。但这种代理有个致命的缺点,就是要创建一个类,并且这个类要继承与要增加增加功能的类一致的接口,由于与接口绑死,不利于扩张。因此有了下面的动态代理。

     接口与DangDang类保持不变,创建一个类继承InvocationHandler接口:

    public class SendBookInvocationHandler implements InvocationHandler{
        private Object object;
        public SendBookInvocationHandler(Object object){
            super();
            this.object = object;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            // TODO Auto-generated method stub
            System.out.println("顺丰接收书籍");
            Object returnValue = method.invoke(object,args);
            System.out.println("顺丰配出书籍");
            return returnValue;
        }
    }

     更改AopTest类main方法的内容:

      public static void main(String[] args) {
            DangDang dangdang = new DangDang();
            ISendBook sendBook = (ISendBook) Proxy.newProxyInstance(AopTest.class.getClassLoader(),
            dangdang.getClass().getInterfaces(),new SendBookInvocationHandler(dangdang));
            sendBook.sendBook();
        }

     运行结果:

    顺丰接收书籍
    当当网-书籍部门,将书送到指定地址的客户手中
    顺丰配出书籍

     同样实现了对DangDang的sendBook方法增强了内容/功能。但这种方式仅仅只用继承唯一指定的接口便可以实现,而不是要继承与类一致的接口。有利于扩展。

      尽管原生态SDK的动态代理能实现功能,但还是不太方便,并且每个程序员的写法会不同,不利于代码风格的一致性与后期维护,因此使用了Spring框架对动态代理进行了封装,方便与维护。

      1. 方法前通知要实现MethodBeforeAdvice接口

      2. 方法后通知要实现AfterReturningAdvice接口

      3. 方法环绕通知要实现MethodInterceptor接口

      4. 异常处理通知要实现 ThrowsAdvice接口

     对上述进行Spring进行动态代理:

      ISendBook接口以及DangDang类不用修改

      添加AfterSentBook类:该类继承了AfterReturningAdvice接口

    public class AfterSentBook implements AfterReturningAdvice{
    
        //Object arg0:返回值
        //Method arg1:方法对象
        //Object[] arg2:参数
        //Object arg3:原始目标被功能增强的对象
        @Override
        public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable {
            // TODO Auto-generated method stub
            System.out.println("AftrSentBook信息,返回值:"+arg0+",方法名称:"+arg1+",方法参数个数:"+arg2.length+
                    ",原始对象:"+arg3);
        }
    }

      添加BeforeSendBook类:该类继承了MethodBeforAdvice接口

    public class BeforeSendBook implements MethodBeforeAdvice{
        //Method arg0 :方法对象
        //Object[] arg1: 方法的参数值
        //Object arg2:原始目标被功能增强的对象
        @Override
        public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
            // TODO Auto-generated method stub
            System.out.println("BeforeSendBook信息,方法名称="+arg0.getName()+",参数个数:"+arg1.length+",原始对象:"+arg2);
        }
    }

      该类继承了MethodTnterceptor接口

    public class RoundSentBook implements MethodInterceptor{
        /**
         * MethodInvocation arg0:类的对象,可以通过此对象,调用以下的方法
         * getArguments(): 获取参数
         * getMethod(): 获取方法对象
         * getThis(): 原始目标被功能增强的对象
         * proceed():调用原始目标对象的指定Method方法,并返回原始目标对象
         * */
        @Override
        public Object invoke(MethodInvocation arg0) throws Throwable {
            // TODO Auto-generated method stub
            System.out.println("MethodInterceptor begin信息,方法名称="+arg0.getMethod().getName()+
                    "参数个数:"+arg0.getArguments()+",原始对象:"+arg0.getThis());
            Object object = arg0.proceed();
            System.out.println("MethodInterceptor end信息,方法名称="+arg0.getMethod().getName()+
                    "参数个数:"+arg0.getArguments()+",原始对象:"+arg0.getThis());
            return object;
        }    
    }

      xml配置文件:

    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:c="http://www.springframework.org/schema/c"
        xmlns:p="http://www.springframework.org/schema/p"
        xmlns:util="http://www.springframework.org/schema/util"
        xsi:schemaLocation="
            http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/util
            http://www.springframework.org/schema/util/spring-util.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd">
    
        <bean id="dangdang" class="Spring.DangDang"></bean>
        <bean id="before" class="Spring.BeforeSendBook"></bean>
        <bean id="after" class="Spring.AfterSentBook"></bean>
        <bean id="round" class="Spring.RoundSentBook"></bean>
        <bean id="error" class="Spring.My_ThrowsAdvice"></bean>
        
        <!--  -->
        <bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
            <property name="interfaces">
                <list>
                    <value>Spring.ISendBook</value>
                </list>
            </property>
            <property name="target" ref="dangdang"></property>
            <property name="interceptorNames">
                <list>
                    <value>round</value>
                    <value>before</value>
                    <value>after</value>
                </list>
            </property>
        </bean>
    </beans>

      AopTest类:

    public class AopTest {
    
        public static void main(String[] args) {    
            ApplicationContext context = new ClassPathXmlApplicationContext("aop-applicationContext.xml");
            ISendBook sendBook = (ISendBook)context.getBean("proxy");
            sendBook.sendBook();
        }
    }

      运行结果如下:

    MethodInterceptor begin信息,方法名称=sendBook参数个数:[Ljava.lang.Object;@63e2203c,原始对象:Spring.DangDang@1efed156
    BeforeSendBook信息,方法名称=sendBook,参数个数:0,原始对象:Spring.DangDang@1efed156
    当当网-书籍部门,将书送到指定地址的客户手中
    AftrSentBook信息,返回值:null,方法名称:public abstract void Spring.ISendBook.sendBook(),方法参数个数:0,原始对象:Spring.DangDang@1efed156
    MethodInterceptor end信息,方法名称=sendBook参数个数:[Ljava.lang.Object;@6737fd8f,原始对象:Spring.DangDang@1efed156

     

     我们可以看到Spring对动态代理进行了封装,但是这种方式一个通用业务需要创建4个类,方法执行前,方法执行后,方法环绕,以及出现异常的情况,假设如果有很多个通用业务,那么就需要创建4*对应通用业务数,尽管有效的对动态代理进行了有效的封装,但如果通用业务多的话,管理起来还是比较复杂,因此Spring 推出了AOP的方式来实现。

    Spring的AOP:

     要知道,Spring的AOP技术原理就是基于代理设计模式的。因此当Spring使用AOP技术的时候,运行的效果往往与动态代理的效果是很类似,或者是是一摸一样的。

     在学习AOP技术之前,首先需要了解几个概念:

      1. 横切关注点

      2.切面

      3. 连接点

      4. 切点

      5. 通知:通知便是定义了在什么时机进行切莫的参数,在Spring的AOP的通知中,分为5种:

       前置通知(Before):方法被调用前

       后置通知(After):方法被调用后

       环绕通知(Around):方法被调用之前与之后

       返回通知(After-returning):方法返回了值后执行

       异常处理(After-throwing):当执行方法中出现异常后触发执行

      6. 织入

     与DI容器/IOC技术一样,Spring实现aop技术也可以分全xml与全注解的形式。它们实现的功能都是相同的,只是编写的形式不一样。

      使用xml方式 DangDang类:

    public class DangDang{
        
        boolean isGet = false;
        
        public void bookBooks(){
            System.out.println("当当网-书籍部门,客户订书了");
        }
        
        public void sendBook() {
            // TODO Auto-generated method stub
            System.out.println("当当网-书籍部门,将书送到指定地址的客户手中");
        }
        
        public boolean isGetBook(){
            System.out.println("客户是否收到书籍");
            return isGet;
        }
    }

      使用xml方式:AspectObject类

    public class AspectObject {
        public void beginRun(){
            System.out.println("前置通知------------");
        }
        
        public void endRun(){
            System.out.println("后置通知------------");
        }
        
        public Object round(ProceedingJoinPoint point){
            System.out.println("前");
            Object returnObject = null;
            try {
                returnObject = point.proceed();
            } catch (Throwable e) {
                e.printStackTrace();
            }
            System.out.println("后");
            return returnObject;
        }
        
        @AfterReturning("execution(* Spring.DangDang.* (..))")
        public void afterRun(){
            System.out.println("返回值通知------------");
        }
        
        public void afterThrowing(){
            System.out.println("异常通知------------");
        }
    }

      使用xml方式:aop-applicationConfig.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:context="http://www.springframework.org/schema/context"
        xmlns:c="http://www.springframework.org/schema/c"
        xmlns:p="http://www.springframework.org/schema/p"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xmlns:util="http://www.springframework.org/schema/util"
        xsi:schemaLocation="
            http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
               http://www.springframework.org/schema/util
            http://www.springframework.org/schema/util/spring-util.xsd
            http://www.springframework.org/schema/aop
            http://www.springframework.org/schema/aop/spring-aop.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd">
    
        <bean id="dangdang" class="Spring.DangDang"></bean>
        <bean id="aspectObject" class="Spring.AspectObject"></bean>
    
        <aop:config>
            <aop:aspect ref="aspectObject">
                <aop:before method="beginRun" pointcut="execution(* Spring.DangDang.bookBooks(..))"/>
                <aop:after method="endRun" pointcut="execution(* Spring.DangDang.bookBooks(..))"/>
                <aop:around method="round" pointcut="execution(* Spring.DangDang.sendBook(..))"/>
                <aop:after-returning method="afterRun" pointcut="execution(* Spring.DangDang.isGetBook(..))"/>
                <aop:after-throwing method="afterThrowing" pointcut="execution(* Spring.DangDang.*(..))"/>
            </aop:aspect>
        </aop:config>
    </beans>

      使用了xml方式:AopTest类

    public class AopTest {
    
        public static void main(String[] args) {
            
            ApplicationContext context = new ClassPathXmlApplicationContext("aop-applicationContext.xml");
            DangDang dangdang = (DangDang) context.getBean("dangdang");
            dangdang.bookBooks();
            System.out.println();
            dangdang.sendBook();
            System.out.println();
            dangdang.isGetBook();
                
        }
    }

      运行结果如下:

    前置通知------------
    当当网-书籍部门,客户订书了
    后置通知------------
    
    前
    当当网-书籍部门,将书送到指定地址的客户手中
    后
    
    客户是否收到书籍
    返回值通知------------

        

      使用注解的方式,DangDang类:

    @Component(value="dangdang1")
    public
    class DangDang{ boolean isGet = false; public void bookBooks(){ System.out.println("当当网-书籍部门,客户订书了"); } public void sendBook() { // TODO Auto-generated method stub System.out.println("当当网-书籍部门,将书送到指定地址的客户手中"); } public boolean isGetBook(){ System.out.println("客户是否收到书籍"); return isGet; } }

      使用注解的方式,AspectObject类:

    @Component
    @Aspect  //必须填写,不然不知道切面要执行的执行体
    public class AspectObject {
        @Before(value="execution(* Spring.DangDang.bookBooks(..))")
        public void beginRun(){
            System.out.println("前置通知------------");
        }
        
        @After(value="execution(* Spring.DangDang.bookBooks(..))")
        public void endRun(){
            System.out.println("后置通知------------");
        }
        
        @Around(value="execution(* Spring.DangDang.sendBook(..))")
        public Object round(ProceedingJoinPoint point){
            System.out.println("前");
            Object returnObject = null;
            try {
                returnObject = point.proceed();
            } catch (Throwable e) {
                e.printStackTrace();
            }
            System.out.println("后");
            return returnObject;
        }
        
        @AfterReturning(value="execution(* Spring.DangDang.isGetBook (..))")
        public void afterRun(){
            System.out.println("返回值通知------------");
        }
        
        @AfterThrowing(value="publicPointcut() and bean(dangdang1)")
        public void afterThrowing(){
            System.out.println("异常通知------------");
        }
    }

      使用注解的方式,AopTest类:

    @EnableAspectJAutoProxy   //必须填写,如无该注解的话,AspectObject类仅仅只是一个普通的类,有该注解,AspectObject才能算的上是切面
    @ComponentScan(basePackages="Spring")
    public class AopTest {
    
        public static void main(String[] args) {
            
            String resource = "Spring";
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AopTest.class);
            DangDang dangdang = (DangDang) context.getBean("dangdang1");
            dangdang.bookBooks(null);
            System.out.println();
            dangdang.sendBook(null,null);
            System.out.println();
            dangdang.isGetBook();
        }
    }

      运行效果与使用xml方式的运行效果一致。

     看到上述使用xml方式与注解方式,最主要的是execution(* Spring.DangDang.bookBooks(..))的表达式,该表达式对应的参数如下:

      第一个代表的是返回值,* 代表任意的返回值

      第二个代表的是指定包下的指定类下的指定方法下的指定参数,Spring.DangDang.bookBooks(..) ,代表的是Spring包下的DangDang类下的bookBooks方法,使用的是任意的bookBooks的参数。括号中代表的是对应方法的参数,每个方法的参数都不一致,因此可以用..来代替任意的参数。若想调用该类的全部方法:Spring.DangDang.*(..)

     可以看到前置与后置的切点都是一致的,为了减少execution表达式,降低冗余的配置,可以将execution表达式进行全局化:

      对应xml方式,改动aop-applicationConfig.xml文件:

    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:c="http://www.springframework.org/schema/c"
        xmlns:p="http://www.springframework.org/schema/p"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xmlns:util="http://www.springframework.org/schema/util"
        xsi:schemaLocation="
            http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
               http://www.springframework.org/schema/util
            http://www.springframework.org/schema/util/spring-util.xsd
            http://www.springframework.org/schema/aop
            http://www.springframework.org/schema/aop/spring-aop.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd">
    
        <bean id="dangdang" class="Spring.DangDang"></bean>
        <bean id="aspectObject" class="Spring.AspectObject"></bean>
    
        <aop:config>
            <!-- 定义全局切点 -->
            <aop:pointcut id="pointcut1" expression="execution(* Spring.DangDang.bookBooks(..))"/>
            <aop:pointcut id="pointcut2" expression="execution(* Spring.DangDang.* (..))" />
            <aop:aspect ref="aspectObject">        
                <aop:before method="beginRun" pointcut-ref="pointcut1"/>
                <aop:after method="endRun" pointcut-ref="pointcut1"/>
                <aop:around method="round" 
                    pointcut="execution(* Spring.DangDang.sendBook(..))"/>
                <aop:after-returning method="afterRun" pointcut="execution(* Spring.DangDang.isGetBook(..))"/>
                <aop:after-throwing method="afterThrowing"/>
            </aop:aspect>
        </aop:config>
    </beans>

      修改后运行AopTest类:运行效果一致

      对应注解的方式,仅改动AspectObject类:

    @Component
    @Aspect  //必须填写,不然不知道切面要执行的执行体
    public class AspectObject {
       @Pointcut(value="execution(* Spring.DangDang.bookBooks(..))")
       public void publicPointcut(){}
    @Before(value
    ="publicPointcut()") public void beginRun(){ System.out.println("前置通知------------"); } @After(value="publicPointcut()") public void endRun(){ System.out.println("后置通知------------"); } @Around(value="execution(* Spring.DangDang.sendBook(..))") public Object round(ProceedingJoinPoint point){ System.out.println("前"); Object returnObject = null; try { returnObject = point.proceed(); } catch (Throwable e) { e.printStackTrace(); } System.out.println("后"); return returnObject; } @AfterReturning(value="execution(* Spring.DangDang.isGetBook (..))") public void afterRun(){ System.out.println("返回值通知------------"); } @AfterThrowing(value="publicPointcut() and bean(dangdang1)") public void afterThrowing(){ System.out.println("异常通知------------"); } }

      修改后运行AopTest类:运行效果一致

     向切面传入参数值:

      如果方法中有参数,切面类也可以接收这个参数,并可以进行预处理。在5种通知中,对于获取方法参数重要的是前置,后置与绕环的通知种类;而返回通知,是获取方法的返回值,异常通知,则是获取方法中出现的异常。

      使用xml的方式,DangDang类:对方法中添加了参数

    @Component(value="dangdang1")
    public class DangDang{
        
        boolean isGet = false;
        
        public void bookBooks(Integer userId){
            System.out.println("当当网-书籍部门,客户订书了");
        }
        
        public void sendBook(Integer userId,Integer orderId) {
            // TODO Auto-generated method stub
            System.out.println("当当网-书籍部门,将书送到指定地址的客户手中");
        }
        
        public boolean isGetBook(){
            System.out.println("客户是否收到书籍");
            return isGet;
        }
    }

      使用xml的方式,AspectObject类:

    public class AspectObject {

       //切面类的方法参数要与对应方法的参数(包括参数的数据类型以及参数名)一致,从而可以获取方法的参数 public void beginRun(Integer userId){ if(userId != null){ System.out.println("客户已登录,userId号为:"+userId); }else{ System.out.println("客户未登陆,已让客户去登录"); userId = 12; System.out.println("客户登录成功,userId号为:"+userId); } } public Integer endRun(Integer userId){ Integer orderId = 120; System.out.println("已生成订单,订单号为:"+orderId); return orderId; } public Object round(ProceedingJoinPoint point,Integer userId,Integer orderId){ System.out.println("前,userId:"+userId+",orderId:"+orderId); Object returnObject = null; try { returnObject = point.proceed(); } catch (Throwable e) { e.printStackTrace(); } System.out.println("后,userId:"+userId+",orderId:"+orderId); return returnObject; } public void afterRun(boolean isGet){ System.out.println("返回值通知------------"); if(isGet){ System.out.println("客户已收到"); }else{ System.out.println("客户未收到"); } }

    public void afterThrowing(Throwable t){ System.out.println("异常通知------------"); System.out.println("aopThrowMethod t="+t.getMessage()); } }

      使用xml方式,aop-applicationConfig.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:context="http://www.springframework.org/schema/context"
        xmlns:c="http://www.springframework.org/schema/c"
        xmlns:p="http://www.springframework.org/schema/p"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xmlns:util="http://www.springframework.org/schema/util"
        xsi:schemaLocation="
            http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
               http://www.springframework.org/schema/util
            http://www.springframework.org/schema/util/spring-util.xsd
            http://www.springframework.org/schema/aop
            http://www.springframework.org/schema/aop/spring-aop.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd">
    
        <bean id="dangdang1" class="Spring.DangDang"></bean>
        <bean id="aspectObject" class="Spring.AspectObject"></bean>
    
        <aop:config>
            <!-- 定义全局切点 -->
            <!-- 全部变量,execution表达式中方法名后面的括号填写参数的数据类型,按照方法的参数顺序填写,
                  在exectution表达式后跟着的是对应方法参数的值,注意的是,一定要用and来连接起来,否则会出错 -->
            <aop:pointcut id="pointcut1" expression="execution(* Spring.DangDang.bookBooks(Integer)) and args(userId)"/>
            <aop:pointcut id="pointcut2" expression="execution(* Spring.DangDang.* (..))" />
            <aop:aspect ref="aspectObject">        
                <aop:before method="beginRun" pointcut-ref="pointcut1"/>
                <aop:after method="endRun" pointcut-ref="pointcut1"/>
                <aop:around method="round" 
                    pointcut="execution(* Spring.DangDang.sendBook(Integer,Integer)) and args(userId,orderId)"/>
                <aop:after-returning method="afterRun" pointcut="execution(* Spring.DangDang.isGetBook(..))" 
                    returning="isGet"/> <-- 返回通知,获取方法的返回值,returning的值与方法返回的值名称是一致的-->
            
           <-- 异常通知,获取方法执行中的异常状态,throwing的方法 -->
    <aop:after-throwing method="afterThrowing" pointcut-ref="pointcut2" throwing="t"/> </aop:aspect> </aop:config> </beans>

      AopTest类:

    public class AopTest {
    
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("aop-applicationContext.xml");
            DangDang dangdang = (DangDang) context.getBean("dangdang1");
            dangdang.bookBooks(1);
            System.out.println();
            dangdang.sendBook(1,120);
            System.out.println();
            dangdang.isGetBook();
        }
    }

      运行效果如下:

    客户已登录,userId号为:1
    当当网-书籍部门,客户订书了
    已生成订单,订单号为:120
    
    前,userId:1,orderId:120
    当当网-书籍部门,将书送到指定地址的客户手中
    后,userId:1,orderId:120
    
    客户是否收到书籍
    返回值通知------------
    客户未收到

      

      使用注解的方式,DangDang类:

    @Component(value="dangdang1")
    public class DangDang{
        
        boolean isGet = false;
        
        public void bookBooks(Integer userId){
            System.out.println("当当网-书籍部门,客户订书了");
        }
        
        public void sendBook(Integer userId,Integer orderId) {
            // TODO Auto-generated method stub
            System.out.println("当当网-书籍部门,将书送到指定地址的客户手中");
        }
        
        public boolean isGetBook(){
            System.out.println("客户是否收到书籍");
            return isGet;
        }
    }

      使用注解的方式,AspectObject类:

    @Component
    @Aspect
    public class AspectObject {
        
       //与xml的value值是一致的 @Pointcut(value="execution(* Spring.DangDang.bookBooks(Integer)) && args(userId)") public void publicPointcut1(Integer userId){} @Pointcut(value="execution(* Spring.DangDang.* (..))") public void publicPointcut(){} @Before(value="publicPointcut1(userId)") public void beginRun(Integer userId){ if(userId != null){ System.out.println("客户已登录,userId号为:"+userId); }else{ System.out.println("客户未登陆,已让客户去登录"); userId = 12; System.out.println("客户登录成功,userId号为:"+userId); } } @After(value="publicPointcut1(userId)") public Integer endRun(Integer userId){ Integer orderId = 120; System.out.println("已生成订单,订单号为:"+orderId); return orderId; } @Around(value="execution(* Spring.DangDang.sendBook(Integer,Integer)) && args(userId,orderId)") public Object round(ProceedingJoinPoint point,Integer userId,Integer orderId){ System.out.println("前,userId:"+userId+",orderId:"+orderId); Object returnObject = null; try { returnObject = point.proceed(); } catch (Throwable e) { e.printStackTrace(); } System.out.println("后,userId:"+userId+",orderId:"+orderId); return returnObject; } //返回通知,是获取方法返回值 @AfterReturning(value="execution(* Spring.DangDang.isGetBook (..))",returning="isGet") public void afterRun(boolean isGet){ System.out.println("返回值通知------------"); if(isGet){ System.out.println("客户已收到"); }else{ System.out.println("客户未收到"); } } //异常通知,是获取方法中出现错误的异常
       @AfterThrowing(value="publicPointcut() and bean(dangdang1)",throwing="t") public void afterThrowing(Throwable t){ System.out.println("异常通知------------"); System.out.println("aopThrowMethod t="+t.getMessage()); } }

      使用注解的方法,AopTest类:

    @EnableAspectJAutoProxy
    @ComponentScan(basePackages="Spring")
    public class AopTest {
    
        public static void main(String[] args) {
            
            String resource = "Spring";
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AopTest.class);
            DangDang dangdang = (DangDang) context.getBean("dangdang1");
            dangdang.bookBooks(null);
            System.out.println();
            dangdang.sendBook(null,null);
            System.out.println();
            dangdang.isGetBook();
        }
    }

      运行AopTest类,运行效果如下:

    客户未登陆,已让客户去登录
    客户登录成功,userId号为:12
    当当网-书籍部门,客户订书了
    已生成订单,订单号为:120
    
    前,userId:null,orderId:null
    当当网-书籍部门,将书送到指定地址的客户手中
    后,userId:null,orderId:null
    
    客户是否收到书籍
    返回值通知------------
    客户未收到

       

      使用半注解半xml的形式:

       使用上述注解方式的AsceptObject与DangDang类

       使用上述xml方式的AopTest类

       改变aop-applicationConfig.xml文件:

    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:c="http://www.springframework.org/schema/c"
        xmlns:p="http://www.springframework.org/schema/p"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xmlns:util="http://www.springframework.org/schema/util"
        xsi:schemaLocation="
            http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
               http://www.springframework.org/schema/util
            http://www.springframework.org/schema/util/spring-util.xsd
            http://www.springframework.org/schema/aop
            http://www.springframework.org/schema/aop/spring-aop.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd">
    
        <!-- 使用全包搜索 -->
        <context:component-scan base-package="Spring"></context:component-scan>
        
        <!-- 使用aop:aspectj-autoproxy标签根据类中的注解来自动完成切点 -->
        <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    </beans>

      运行AopTest类,运行效果如下:

    客户已登录,userId号为:1
    当当网-书籍部门,客户订书了
    已生成订单,订单号为:120
    
    前,userId:1,orderId:120
    当当网-书籍部门,将书送到指定地址的客户手中
    后,userId:1,orderId:120
    
    客户是否收到书籍
    返回值通知------------
    客户未收到
  • 相关阅读:
    用Maven插件生成Mybatis代码
    年薪50万的大数据分析师养成记
    利用 index、explain和profile优化mysql数据库查询小结
    perl MQSeries::Queue sync方法
    新零售不简单,当初马云自己都没解释清楚!
    新零售不简单,当初马云自己都没解释清楚!
    elasticsearch 默认不支持检索hadoop
    以不能久驻世上的心态处理日常事务——北漂18年(89)
    数据化管理在餐饮业中的应用
    解决Linux出现"Device eth0 does not seem to be present"问题
  • 原文地址:https://www.cnblogs.com/hjlin/p/11469832.html
Copyright © 2020-2023  润新知