• Spring的AOP


    一、实现自己的AOP

    在之前一篇随笔中已经详细讲解了java的动态代理机制,我们也知道了AOP的底层其实就是基于动态代理机制实现的,所以这里先自己实现一下AOP

    public class DynamicProxy implements InvocationHandler
    {
        // 要代理的对象
        private Object target;
    
        // 将构造方法禁用掉,不让外部通过new来得到DynamicProxy对象
        private DynamicProxy()
        {
        };
    
        /**
         * 返回一个动态的代理对象
         * 
         * @param object
         * @return
         */
        public static Object newInstance(Object object)
        {
            DynamicProxy proxy = new DynamicProxy();
            proxy.target = object;
            //    通过Proxy的newProxyInstance方法来得到一个代理对象
            Object result = Proxy.newProxyInstance(object.getClass()
                    .getClassLoader(), object.getClass().getInterfaces(), proxy);
            return result;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable
        {
    //        //    只有方法名为add和delete时候才引入日志
    //        if(method.getName().equals("add") || method.getName().equals("delete"))
    //        {
    //            Logger.logInfo("动态代理类");
    //        }
            
            // 根据LogAnnotation来判断,如果被标注了注解,则输出日志
            if(method.isAnnotationPresent(LogAnnotation.class))
            {
                LogAnnotation log = method.getAnnotation(LogAnnotation.class);
                Logger.logInfo(log.value());
            }
            
            Object object = method.invoke(target, args);
            return object;
        }
    }

    就如上篇随笔所说,动态代理类必须要实现InvocationHandler的这个接口,我们的这个类当然也要实现这个接口了。然后在里面定义了一个私有的Object属性,表示我们要代理的对象。这里我们将这个类的构造方法禁用掉,使其不能通过外部直接new出来一个对象,然后我们写一个newInstance的方法来给我们的代理对象赋初值,并且返回的就是我们的代理对象。我们看看在beans.xml中的配置文件

    <!-- 如果要对static方法进行注入,可以通过factory-method属性来制定方法名字,并通过构造函数的方式传入参数 -->
            <bean id="userDAOProxy" class="com.xiaoluo.proxy.DynamicProxy" factory-method="newInstance">
                <constructor-arg ref="userDAO"/>
            </bean>

    因为我们的DynamicProxy类的对象以及代理对象是通过static方法来进行注入的,因此我们如果要对其进行注入的话,需要通过 factory-method 这个属性来给我们的静态方法进行属性注入,通过 <constructor-arg>来讲参数传递进去,这样我们的userDAOProxy就是一个代理对象了。

    二、通过Annotation来配置我们的AOP

    我们要将AOP的schema引入,如果使用注解的话,还要开启AOP的自动代理

    <?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:aop="http://www.springframework.org/schema/aop"
         xsi:schemaLocation="http://www.springframework.org/schema/beans
             http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
             http://www.springframework.org/schema/context
             http://www.springframework.org/schema/context/spring-context-3.0.xsd
             http://www.springframework.org/schema/aop
             http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
            
            <!-- 通过annotation来进行bean的创建 -->
            <context:annotation-config/>
            <!-- 对以com.xiaoluo开头的包进行扫描 -->
            <context:component-scan base-package="com.xiaoluo"/>
            <!-- 开启AOP的自动代理,只要加入了@Aspect标签就自动代理 -->
            <aop:aspectj-autoproxy/>
            
    </beans>

    然后我们来看看我们的切面类:

    @Component("logAspect")    //    将该切面类由Spring托管
    @Aspect    //    声明该类是一个Aspect,切面类
    public class LogAspect
    {
        /**
         * execution(* com.xiaoluo.dao.*.add*(..))
         * 第一个*表示任意返回值
         * 第二个*表示com.xiaoluo.dao下的所有类
         * 第三个*表示所有以add开头的方法
         * (..)表示方法接收的任何参数
         */
        /*
         * Before在方法执行前执行
         */
        @Before("execution(* com.xiaoluo.dao.*.add*(..))||" +
                "execution(* com.xiaoluo.dao.*.delete*(..))||" +
                "execution(* com.xiaoluo.dao.*.update*(..))")
        public void logStart(JoinPoint jp)
        {
            //    得到该JoinPoint的类
            System.out.println(jp.getTarget());
            //    得到该JoinPoint的方法
            System.out.println(jp.getSignature());
            //    得到该JoinPoint的方法的名字
            System.out.println(jp.getSignature().getName());
            Logger.logInfo("日志开始");
        }
        
        /*
         * After在方法执行只会执行
         */
        @After("execution(* com.xiaoluo.dao.*.add*(..))||" +
                "execution(* com.xiaoluo.dao.*.delete*(..))||" +
                "execution(* com.xiaoluo.dao.*.update*(..))")
        public void logEnd()
        {
            Logger.logInfo("日志结束");
        }
        
        /*
         * Around包含了这个方法的执行
         * 
         * Logger.logInfo("开始执行Around日志");
         * pjp.proceed();
         * Logger.logInfo("结束了Around日志");的执行顺序为:
         * 
         * 首先执行 Logger.logInfo("开始执行Around日志");,接着执行方法,因为在方法执行要执行
         * Before,所以先执行完Before再执行方法,接着执行  Logger.logInfo("结束了Around日志");
         * 最后执行After
         * 
         */
        @Around("execution(* com.xiaoluo.dao.*.add*(..))||" +
                "execution(* com.xiaoluo.dao.*.delete*(..))||" +
                "execution(* com.xiaoluo.dao.*.update*(..))")
        public void logAround(ProceedingJoinPoint pjp) throws Throwable
        {
            Logger.logInfo("开始执行Around日志");
            pjp.proceed();
            Logger.logInfo("结束了Around日志");
        }
    }

    因为Spring的AOP使用的是第三方的jar包,所以我们这里还要引入三个AOP的jar文件:

    aopalliance-1.0.jar
    aspectjrt-1.7.3.jar
    aspectjweaver-1.7.3.jar

    这样我们的基于注解的AOP就配置好可以使用了。

    三、基于XML的AOP配置

    如果基于XML的AOP配置,我们的beans.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:aop="http://www.springframework.org/schema/aop"
         xsi:schemaLocation="http://www.springframework.org/schema/beans
             http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
             http://www.springframework.org/schema/context
             http://www.springframework.org/schema/context/spring-context-3.0.xsd
             http://www.springframework.org/schema/aop
             http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
            
            <!-- 通过annotation来进行bean的创建 -->
            <context:annotation-config/>
            <!-- 对以com.xiaoluo开头的包进行扫描 -->
            <context:component-scan base-package="com.xiaoluo"/>
            <!-- 通过xml方式来配置AOP -->
            <aop:config>
                <!-- 声明一个切面 -->
                <aop:aspect id="myLogAspect" ref="logAspect">
                    <!-- 声明在哪些位置我要加入这个切面 -->
                    <aop:pointcut id="logPoint" expression="execution(* com.xiaoluo.dao.*.add*(..))||
                                                            execution(* com.xiaoluo.dao.*.delete*(..))||
                                                            execution(* com.xiaoluo.dao.*.update*(..))"/>
                    <aop:before method="logStart" pointcut-ref="logPoint"/>
                    <aop:after method="logEnd" pointcut-ref="logPoint"/>
                    <aop:around method="logAround" pointcut-ref="logPoint"/>                
                </aop:aspect>
            </aop:config>        
    </beans>

    我们这里当然也要声明我们的切面类:

    @Component("logAspect")    //    将该切面类由Spring托管
    public class LogAspect
    {
        public void logStart(JoinPoint jp)
        {
            //    得到该JoinPoint的类
            System.out.println(jp.getTarget());
            //    得到该JoinPoint的方法
            System.out.println(jp.getSignature());
            //    得到该JoinPoint的方法的名字
            System.out.println(jp.getSignature().getName());
            Logger.logInfo("日志开始");
        }
        
        public void logEnd()
        {
            Logger.logInfo("日志结束");
        }
        
        public void logAround(ProceedingJoinPoint pjp) throws Throwable
        {
            Logger.logInfo("开始执行Around日志");
            pjp.proceed();
            Logger.logInfo("结束了Around日志");
        }
    }

    本篇随笔主要记录了自己实现AOP的配置以及基于Annotation和XML的方式来配置我们的AOP

  • 相关阅读:
    手机网站调试神器之chrome控制台
    改善C#程序的建议2:C#中dynamic的正确用法
    flowplayer视频播放插件[转]
    Python类,特殊方法, __getitem__,__len__, __delitem__
    Python yield 使用浅析
    Openerp负载平衡
    linux sheel重复执行上条命令
    Python 去除列表中重复的元素
    去除Odoo主页中的提示: Your Odoo is not supported.
    Python 正则表达式学习摘要及资料
  • 原文地址:https://www.cnblogs.com/xiaoluo501395377/p/3384821.html
Copyright © 2020-2023  润新知