• AOP 面向切面编程


    AOP学习

    AOP概述

      AOP(Aspect Oriented Programming)是面向切面编程,是OOP的扩展,可以解决OOP代码开发过程中遇到的问题。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

    AOP的应用场景

      应用场景有很多,这里只列举一小部分

    • 打印操作日志,防止小伙伴删库跑路
    • 测试系统性能
    • 事务控制

    AOP和Spring AOP、AspectJ

    • AOP最早是AOP联盟提出的,并且制定规范
    • Spring AOP 遵循AOP规范,Spring AOP只能在Spring中使用
    • AspectJ是一个面向切面的框架,它扩展了Java语言,AspectJ定义了AOP语法。Aspect可以在Spring框架以及其他框架内使用

    AOP实现原理

    AOP实现是通过动态代理实现的

    • jdk动态代理: 对实现接口的类产生代理
    • cglib动态代理:对没有实现接口的类产生代理

    Spring底层如果类实现了接口用jdk动态代理,没有实现接口默认用CGLIB动态代理。当然这是默认的,如果需要也可以强制使用。当然这是后话了

      

    /**
     * JDK动态代理,利用反射完成
     */
    public class JdkProxy implements InvocationHandler {
        private Object target;
    
        public JdkProxy(Class target) {
            this.target = target;
        }
    
        @Override
        public Object invoke(Object target, Method method, Object[] args) throws Throwable {
    
            System.out.println("===before===");
            Object obj = method.invoke(target, args);
            System.out.println("===after===");
            return obj;
        }
    
        public Object getProxy() {
            return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
                    this);
        }
    }
    JDK动态代理
    /**
     * Cglib动态代理,通过继承生成目标类的代理类
     */
    public class CglibProxy implements MethodInterceptor {
    
        private Object target;
        public CglibProxy(Object target) {
            this.target = target;
        }
        @Override
        public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            //方法前增强
            System.out.println("***before***");
            Object obj = methodProxy.invoke(proxy, args);
            //方法后增强
            System.out.println("***after****");
            return obj;
        }
    
        public Object getInstance() {
            //创建增强器
            Enhancer enhancer = new Enhancer();
            //设置父类
            enhancer.setSuperclass(this.target.getClass());
            //设置回调
            enhancer.setCallback(this);
            //返回对象
            Object obj = enhancer.create();
            return obj;
        }
    }
    Cglib 动态代理
    Cglib动态代理,要记得引包
    <!-- https://mvnrepository.com/artifact/cglib/cglib -->
    <dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.2.8</version>
    </dependency>

    AOP相关术语

    • Joincut :连接点,可以理解为被拦截的点
    • Pointcut: 切入点,实际上被拦截的点。因为项目中有许多能够被拦截的方法,我们只需根据需求拦截方法
    • Advice: 通知,也叫做增强,可以理解为对方法的增强。比如要在方法的前面增加业务逻辑
    • Introduction:引介,对类的增强,很少用。除非需要更改被代理类的内部属性
    • Weaving: 织入,把通知应用到目标对象的过程
    • Aspect: 切面,是多个通知和切入点的组合
    • Target: 目标对象
    • Proxy: 代理对象

    Spring中五种通知类型

    • @Before: 前置通知,在方法之前增强
    • @After: 后置通知,在方法之后增强
    • @AfterReturing: 后置返回通知,可以接收方法的返回值
    • @AfterThrowing: 异常抛出通知,方法有异常的时候执行
    • @Around: 环绕通知,可以在方法执行前和执行后进行增强。事务就是用@Around实现的

    Spring整合AOP

     github项目源码地址: https://github.com/AmberBar/Learning/tree/master/SpringAOP

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>groupId</groupId>
        <artifactId>SpringAOP</artifactId>
        <version>1.0-SNAPSHOT</version>
    
        <dependencies>
            <!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-core</artifactId>
                <version>4.3.10.RELEASE</version>
            </dependency>
    
            <!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-beans</artifactId>
                <version>4.0.8.RELEASE</version>
            </dependency>
    
            <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>4.0.8.RELEASE</version>
            </dependency>
    
            <!-- https://mvnrepository.com/artifact/junit/junit -->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.8.2</version>
                <!--<scope>test</scope>-->
            </dependency>
            <!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-test</artifactId>
                <version>4.0.8.RELEASE</version>
                <scope>test</scope>
            </dependency>
    
            <!-- https://mvnrepository.com/artifact/cglib/cglib -->
            <dependency>
                <groupId>cglib</groupId>
                <artifactId>cglib</artifactId>
                <version>3.2.8</version>
            </dependency>
    
            <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>1.9.1</version>
            </dependency>
    
        </dependencies>
    </project>
    pom.xml
    package com.amber.dao;
    
    public interface ProductDao {
    
        void create();
    
        void delete();
    
        String update();
    
        void addBatch();
    
        void delBatch();
    }
    ProductDao
    package com.amber.dao;
    
    public class ProduceDaoImpl implements ProductDao {
    
        @Override
        public void create() {
            System.out.println("=========this is create method ==============");
        }
    
        @Override
        public void delete() {
            System.out.println("=========this is delete method ==============");
        }
    
        @Override
        public String update() {
            System.out.println("=========this is update method ==============");
            return "amber";
        }
    
        @Override
        public void addBatch() {
            System.out.println("=========this is addBatch method ==============");
        }
    
        @Override
        public void delBatch() {
            System.out.println("=========this is delBatch method ==============");
            int i = 1/0;
        }
    }
    ProduceDaoImpl 

    基于Xml的形式

    <?xml version="1.0" encoding="utf-8" ?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           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">
    
        <!--配置扫描-->
        <context:component-scan base-package="com.amber"> </context:component-scan>
        <bean id="userDao" class="com.amber.dao.ProduceDaoImpl"></bean>
        <bean id="aspectOption" class="com.amber.aspect.AspectOption"></bean>
    
        <!--xml aop配置-->
        <aop:config>
            <!--设置切入点-->
            <aop:pointcut id="create" expression="execution(* com.amber.dao.ProductDao.create(..))" ></aop:pointcut>
            <aop:pointcut id="delete" expression="execution(* com.amber.dao.ProductDao.delete(..))" ></aop:pointcut>
            <aop:pointcut id="delBatch" expression="execution(* com.amber.dao.ProductDao.delBatch(..))" ></aop:pointcut>
            <aop:pointcut id="addBatch" expression="execution(* com.amber.dao.ProductDao.addBatch(..))" ></aop:pointcut>
            <aop:pointcut id="update" expression="execution(* com.amber.dao.ProductDao.update(..))" ></aop:pointcut>
            <!--设置切面类-->
            <aop:aspect ref="aspectOption">
                <!--设置前置通知-->
                <aop:before method="before" pointcut-ref="create"></aop:before>
                <!--设置后置通知-->
                <aop:after method="after" pointcut-ref="delete"></aop:after>
                <!--环绕通知-->
                <aop:around method="around" pointcut-ref="addBatch"></aop:around>
                <!--设置后置返回通知-->
                <aop:after-returning method="afterReturning" pointcut-ref="update" returning="result"></aop:after-returning>
                <!--设置后置异常通知-->
                <aop:after-throwing method="afterThrowing" pointcut-ref="delBatch" throwing="e"></aop:after-throwing>
            </aop:aspect>
        </aop:config>
    </beans>
    applicationContext_xml.xml
    package com.amber.xml;
    
    import com.amber.dao.ProductDao;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:applicationContext_xml.xml")
    public class ProductDaoTest {
    
        @Autowired
        ProductDao productDao;
    
        @Test
        public void beforeTest() {
            productDao.create();
        }
    
        @Test
        public void afterTest() {
            productDao.delete();
        }
    
        @Test
        public void afterReturingTest() {
            productDao.update();
        }
    
        @Test
        public void aroundTest() {
            productDao.addBatch();
        }
    
        @Test
        public void delBatchTest() {
            productDao.delBatch();
        }
    
    }
    测试

    基于注解形式

    package com.amber.xml;
    
    import com.amber.dao.ProductDao;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:applicationContext_xml.xml")
    public class ProductDaoTest {
    
        @Autowired
        ProductDao productDao;
    
        @Test
        public void beforeTest() {
            productDao.create();
        }
    
        @Test
        public void afterTest() {
            productDao.delete();
        }
    
        @Test
        public void afterReturingTest() {
            productDao.update();
        }
    
        @Test
        public void aroundTest() {
            productDao.addBatch();
        }
    
        @Test
        public void delBatchTest() {
            productDao.delBatch();
        }
    
    }
    测试
    <?xml version="1.0" encoding="utf-8" ?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           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">
    
        <!--配置扫描-->
        <context:component-scan base-package="com.amber"> </context:component-scan>
        <bean id="userDao" class="com.amber.dao.ProduceDaoImpl"></bean>
        <bean id="aspectOption" class="com.amber.aspect.AspectOption"></bean>
    
        <!--配置注解代理-->
        <aop:aspectj-autoproxy ></aop:aspectj-autoproxy>
    </beans>
    ApplicationContext.xml
    package com.amber.xml.aspect;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.*;
    
    /**
     * 基于注解
     */
    @Aspect
    public class AspectOption {
    
        /**
         * 前置增强,在方法之前执行
         */
    
        public void before() {
            System.out.println("AspectOption before");
        }
    
        /**
         * 后置增强,在方法执行之后执行
         */
    
        public void after() {
            System.out.println("AspectOption after");
        }
    
        /**
         * 后置通知增强,可以获取到方法的返回值
         * @param result
         */
    
        public void afterReturning(String result) {
            System.out.println("AspectOption afterReturning " + result);
        }
    
        /**
         * 环绕通知,在方法执行之前和执行之后运行
         * @param joinPoint
         */
    
        public void around(ProceedingJoinPoint joinPoint) {
            System.out.println("AspectOption around before");
            try {
                Object obj = joinPoint.proceed();
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
            System.out.println("AspectOption around after");
        }
    
        /**
         * 异常抛出通知,方法抛出异常的时候执行
         * @param e
         */
    
        public void afterReturing(Throwable e) {
            System.out.println("AspectOption afterReturing");
            System.out.println(e);
        }
    }
    AspectOption
  • 相关阅读:
    GridView使用技巧
    ilspy反编译
    Editplus php
    SQL 日期相减(间隔)datediff函数
    cmd创建文件命令
    iis7 bug解决
    删除qq互联
    discuz 数据库文件密码修改
    linux zip命令
    asp.net调用js方法
  • 原文地址:https://www.cnblogs.com/amberbar/p/9763941.html
Copyright © 2020-2023  润新知