zoukankan      html  css  js  c++  java
  • Spring(AOP部分)

    AOP是什么?

    Aspect Oriented Programming,面向切面编程,它是一种设计方法,通过预编译方法和运行期间动态代理实现,在不改变源代码的基础上,添加新的功能;对业务逻辑的各个部分进行隔离,降低耦合度

    什么是动态代理?

    动态代理对象是原对象的代理,可以使用原对象的方法,在原方法基础上添加新的功能。

    实现动态代理的方式

    1.有接口的JDK动态代理:通过Proxy.newProxyInstance方法,第三个参数即将代理的对象,返回一个代理对象。

    public class Demo {
        /**
         * 演示有接口情况加下的动态代理方式
         */
        @Test
        public void demo1(){
            Class[] classes = {UserDao.class};
            UserDao o = (UserDao)Proxy.newProxyInstance(Demo.class.getClassLoader(), classes,new InvocationHandlerImpl(new UserDaoImpl()));
            o.update();
        }
    
    }
    
    class InvocationHandlerImpl implements InvocationHandler{
        private Object obj;
    
        InvocationHandlerImpl(Object obj){
            this.obj = obj;
        }
    
        //这里添加增加的方法的逻辑
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println(method.getName() + "方法执行前做的处理");
            Object result = method.invoke(this.obj, args);
            System.out.println(method.getName() + "方法执行后的做的处理");
            return result;
        }
    }
    

    2.无接口的CGLIB动态代理:通过继承父类,类似super().method这种形式调用原方法。

    各种概念

    连接点:可以被增强的方法

    切入点:实际被增强的方法

    通知:增强的方法中被增加的逻辑

    • 前置通知 @Before
    • 后置通知 @AfterReturning (有异常则不执行)
    • 环绕通知 @Round
    • 异常通知 @AfterThrowing
    • 最终通知 @After (不管有无异常抛出,都执行)

    切面:把通知应用到切入点的过程

    切面表达式:各种通知内的value值,execution(访问修饰符.被代理的类的全路径.方法名(..))

    @Pointcut:相同切入点的抽取

    @Order:在增强类上面添加该注解,值也小优先级越高

    基于XML配置实现AOP操作

    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:contex="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.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/aop
            http://www.springframework.org/schema/aop/spring-aop.xsd">
        
        <!--启用使用Spring AOP @AspectJ风格的-->
        <aop:aspectj-autoproxy>
        </aop:aspectj-autoproxy>
    
        <bean id="xmlBook" class="aop.bean.XmlBook"/>
        <bean id="myAspectj" class="aop.aspect.XmlForAspectJ"/>
    
        <aop:config>
            <aop:aspect ref="myAspectj">
                <aop:pointcut id="point" expression="execution(* aop.bean.XmlBook.*(..))"/>
                <!--环绕通知和前置通知,哪个位置在前,就先调用哪个-->
                <aop:after method="after" pointcut-ref="point"/>
                <aop:around method="around" pointcut-ref="point"/>
                <aop:before method="before" pointcut-ref="point"/>
                <aop:after-returning method="afterReturning" pointcut-ref="point"/>
                <aop:after-throwing method="afterThrowing" pointcut-ref="point" throwing="e"/>
            </aop:aspect>
        </aop:config>
    </beans>
    

    动态代理类或者说增强的类:

    package aop.aspect;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    
    public class XmlForAspectJ {
        public void before(JoinPoint joinPoint) {
            System.out.println("xml 前置通知:" + joinPoint.getSignature().getName());
        }
    
        public void after(JoinPoint joinPoint) {
            System.out.println("xml 最终通知:" + joinPoint.getSignature().getName());
        }
    
        public void afterReturning(JoinPoint joinPoint) {
            System.out.println("xml 后置通知:" + joinPoint.getSignature().getName());
        }
    
        public void afterThrowing(JoinPoint joinPoint, Throwable e) {
            System.out.println("xml 异常通知:" + joinPoint.getSignature().getName() + ":" + e.getMessage());
        }
    
        public Object around(ProceedingJoinPoint pjp) throws Throwable {
            System.out.println("xml 环绕通知 before..");
            Object proceed = pjp.proceed();
            System.out.println("xml 环绕通知 after..");
            return proceed;
        }
    }
    

    测试类:

    @Test
    public void demo3(){
        ApplicationContext context = new ClassPathXmlApplicationContext("aop.xml");
        XmlBook xmlBook = (XmlBook) context.getBean("xmlBook");
        xmlBook.add();
    }
    

    正常执行情况下,输出:

    xml 环绕通知 before..
    xml 前置通知:add
    Xml book add function
    xml 最终通知:add
    xml 环绕通知 after..
    xml 后置通知:add
    

    当代理的方法出现异常时,输出:

    xml 环绕通知 before..
    xml 前置通知:add
    xml 最终通知:add
    xml 异常通知:add:/ by zero
    

    基于完全注解方式实现AOP操作

    定义配置类:

    @Configuration
    @ComponentScan(basePackages = "aop")
    @EnableAspectJAutoProxy(exposeProxy = true)  // 相当于aop.xml中<aop:aspectj-autoproxy/>
    public class SpringConfig {
    }
    

    定义代理类:

    package aop.aspect;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.*;
    import org.springframework.stereotype.Component;
    @Component
    @Aspect
    public class AnnForAspectJ {
        // 声明切入点(实际被增强的方法),这里AnnBook所有的方法都可以被增强
        @Pointcut(value = "execution(* aop.bean.AnnBook.*(..))")
        public void point(){}
    
        @Before(value = "point()")
        public void before(){
            System.out.println("Ann before...");
        }
    
        @After(value = "point()")
        public void after(){
            System.out.println("Ann after...");
        }
    
        @AfterReturning(value = "point()")
        public void afterReturning(){
            System.out.println("Ann after returning...");
        }
    
        @AfterThrowing(value = "point()")
        public void afterThrowing(){
            System.out.println("Ann after throwing");
        }
    
        @Around(value = "point()")
        public Object around(ProceedingJoinPoint pjp) throws Throwable {
            System.out.println("Ann around before..");
            Object proceed = pjp.proceed();
            System.out.println("Ann around after..");
            return proceed;
        }
    }
    

    测试:

    @Test
    public void demo2(){
        ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        AnnBook annBook = (AnnBook) context.getBean("annBook");
        annBook.add();
    }
    
  • 相关阅读:
    Spring使用@Value注解各种类型的值
    Jdom生成xml文件时的特殊字符问题
    将博客搬至CSDN
    ubuntu/mint添加字体
    linux保持ssh连接
    servlet 重定向与转发区别
    u盘写保护
    修改默认终端
    sudo apt-get update 无法获得锁
    logback多线程日志MDC
  • 原文地址:https://www.cnblogs.com/main404/p/13255284.html
Copyright © 2011-2022 走看看