栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring5之AOP

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring5之AOP

文章目录
  • 一、什么是AOP?
  • 二、AOP底层原理
    • 1. AOP底层使用动态代理
    • 2. JDK动态代理(工厂模式的内容)
  • 三、AOP术语介绍
    • 1. 基础概念
    • 2. 通知类型
  • 四、AOP操作
    • 1. 准备工作
      • (1) Spring框架一般都是基于AspectJ实现AOP操作
      • (2) 基于AspectJ实现AOP操作
      • (3) 在项目工程中引入AOP相关依赖
      • (4) 切入点表达式
    • 2. 通过xml配置AspectJ完成AOP
    • 3. 通过全注解AspectJ完成AOP

一、什么是AOP?

AOP(Aspect Oriented Programming),即面向切面编程,是OOP的补充,它也提供了模块化。在面向对象编程中,关键的单元是对象,AOP的关键单元是切面,或者说关注点(可以简单地理解为你程序中的独立模块)。一些切面可能有集中的代码,但是有些可能被分散或者混杂在一起,例如日志或者事务。这些分散的切面被称为横切关注点。一个横切关注点是一个可以影响到整个应用的关注点,而且应该被尽量地集中到代码的一个地方,例如事务管理、权限、日志、安全等。

AOP让你可以使用简单可插拔的配置,在实际逻辑执行之前、之后或周围动态添加横切关注点。这让代码在当下和将来都变得易于维护。如果你是使用XML来使用切面的话,要添加或删除关注点,你不用重新编译完整的源代码,而仅仅需要修改配置文件就可以了。

二、AOP底层原理 1. AOP底层使用动态代理

有两种情况动态代理
第一种:有接口情况,使用JDK动态代理

第二种:没有接口情况,使用CGLIB动态代理

2. JDK动态代理(工厂模式的内容)

需求:需要对一个实现了Human接口的Superman类进行功能的增强。

interface Human{
    String belief();
    void eat(String food);
}

//被代理类
class Superman implements Human{
    @Override
    public String belief() {
        return "I BELIEVE I CAN FLY";
    }

    @Override
    public void eat(String food) {
        System.out.println("I like eating "+food);
    }
}

要想实现动态代理,需要解决以下问题:

  • 如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象?
  • 当通过代理类的对象调用方法时,如何动态的去调用被代理类中的同名方法?
//代理工厂
class ProxyFactory{
    public static Object getProxyInstance(Object obj){//obj:被代理的类对象,类型为Object方便扩展
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),
                obj.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("方法前增强"+method.getName()+"...."+ Arrays.toString(args));
                        Object res = method.invoke(obj,args);
                        System.out.println("方法后增强"+method.getName()+"...."+ Arrays.toString(args));
                        return res;
                    }
                });
    }
}

参数说明

 public static Object newProxyInstance(ClassLoader loader,
                                          Class[] interfaces,
                                          InvocationHandler h)


public Object invoke(Object proxy, Method method, Object[] args)

测试类

public class DynamicProxy {
    @Test
    public void testDynamicProxy(){
        Superman superman = new Superman();
        Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superman);
        System.out.println(proxyInstance.belief());
        proxyInstance.eat("干锅牛肉");
    }
}
三、AOP术语介绍 1. 基础概念

切面(Aspect):AOP核心就是切面,它将多个类的通用行为封装成可重用的模块,该模块含有一组API提供横切功能。比如,一个日志模块可以被称作日志的AOP切面。根据需求的不同,一个应用程序可以有若干切面。在Spring AOP中,切面通过带有@Aspect注解的类实现。
(个人理解:是动作,把通知应用到切入点的过程)

连接点(Join Point):在程序执行过程中的一点,例如方法的执行或异常的处理。在Spring AOP中,连接点始终代表方法的执行。
(个人理解:被增强类中哪些方法可以被增强)

通知(Advice):AOP在特定的切入点上执行的增强处理,有before, after, afterReturning, afterThrowing, around
(个人理解:实际被增强的逻辑部分)
切入点(Point cut):决定处理如权限校验、日志记录等在何处切入业务代码中(即织入切面)。切点分为execution方式和annotation方式。前者可以用路径表达式指定哪些类织入切面,后者可以指定被哪些注解修饰的代码织入切面。
(个人理解:被增强类中实际被增强的方法)

引介(Introduction):引介让一个切面可以声明被通知的对象实现了任何他们没有真正实现的额外接口,而且为这些对象提供接口的实现使用 @DeclareParaents 注解来生成一个引介。

目标对象(Target object):一个或多个切面通知的对象。也称为通知对象。由于Spring AOP是使用运行时代理实现的,因此该对象将始终是代理对象。

AOP代理(AOP proxy):由AOP框架创建的对象,用于实施Aspect(处理方法执行等)。在Spring Framework中,AOP代理是JDK动态代理或CGLIB代理。

织入(Weaving):织入,就是通过动态代理,在目标对象方法中执行处理内容的过程。

2. 通知类型

中文各个文章称呼不同,理解英文意义。
前置通知(Before Advice):
在连接点之前执行的Advice,使用 @Before 注解使用这个Advice。
返回通知(After Retuning Advice):
在方法返回值之后执行的Advice。如果有异常就没法正常返回值,自然不执行。通过 @AfterReturning 注解来使用。
异常通知(After Throwing Advice):
如果一个方法通过抛出异常来退出的话,这个Advice就会被执行。通过 @AfterThrowing 注解来使用。
后置通知(After Advice):
无论连接点是通过什么方式退出的(正常返回或者抛出异常)都会执行在结束后执行这些Advice。通过 @After 注解使用。
环绕通知(Around Advice):
环绕连接点执行的Advice,通过 @Around 注解使用。

四、AOP操作 1. 准备工作 (1) Spring框架一般都是基于AspectJ实现AOP操作
  • 什么是AspectJ?
  • AspectJ不是Sping组成部分,是一个独立AOP框架,一般把AspectJ和Sping框架一起使用,进行AOP操作
(2) 基于AspectJ实现AOP操作
  • 方法一:基于XML配置文件实现
  • 方法二:基于注解方式实现(使用)
(3) 在项目工程中引入AOP相关依赖

以Maven引入为例:


        
            org.aspectj
            aspectjtools
            1.9.5
        

        
            aopalliance
            aopalliance
            1.0
        

        
            org.aspectj
            aspectjweaver
            1.9.0
        

        
            cglib
            cglib
            3.3.0
        
(4) 切入点表达式
  • 切入点表达式作用;知道对哪个类里的哪个方法进行增强
  • 语法结构:execution([权限修饰符] [返回类型] [类全路径] [方法名称] ([参数列表]))
  • 注意:权限修饰符可以省略;返回类型,类的部分路径,方法名称均可以使用通配符*代替,参数列表可以用..代替。
  • 举例:对SpringAOP.AOPanno类里的add方法进行增强 execution(* SpringAOP.AOPanno.add(..))
2. 通过xml配置AspectJ完成AOP
  • 添加项目xml配置文件


    
    

    
    

  • 使用@Component注释,创建对象
@Component
public class User {
    public void add(){
        System.out.println("add......");
    }
}
  • 创建增强类,编写增强逻辑 (演示不同的通知类型)
@Component
@Aspect     // 生成代理对象
//@Order(3) //如果有多个增强类对同一个方法进行增强,在类上使用@Order(数字类型值),数字越小优先级越高
public class UserProxy {
	
    
    @Pointcut(value = "execution(* SpringAOP.AOPanno.User.add(..))")
    public void pointCut(){
    }
    
    @Before(value = "pointCut()")
    public void before(){
        System.out.println("before...");
    }

    
    @AfterReturning(value = "execution(* SpringAOP.AOPanno.User.add(..))")
    public void afterReturning(){
        System.out.println("afterReturning...");
    }

    
    @AfterThrowing(value = "execution(* SpringAOP.AOPanno.User.add(..))")
    public void afterThrowing(){
        System.out.println("afterThrowing...");
    }

    
    @After(value = "execution(* SpringAOP.AOPanno.User.add(..))")
    public void after(){
        System.out.println("after...");
    }

    
    @Around(value = "execution(* SpringAOP.AOPanno.User.add(..))")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕之前...");
        // 被增强的方法执行
        proceedingJoinPoint.proceed();
        System.out.println("环绕之后...");
    }
    
  • 测试方法
    @Test
    public void tesAopAnno(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean1.xml");
        UserService userService = applicationContext.getBean("user",UserService.class);
        userService.add();
    }
3. 通过全注解AspectJ完成AOP
  • 创建配置类
@Configuration  //作为配置类,替代xml配置文件
@ComponentScan(basePackages = "SpringAOP") //注解扫描,与xml中用法相同
@EnableAspectJAutoProxy(proxyTargetClass = true) //开启AOP代理自动配置,不写这个所有的切面注解将不会生效
public class SpringConfig {
}
  • 增强部分与XML配置方法相同(略)

  • 测试方法

    public void testAOPAnno(){
        ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        User user = context.getBean("user",User.class);
        user.add();
    }
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/863257.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号