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

spring-aop 学习记录

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

spring-aop 学习记录

文章目录
  • spring-aop 学习记录
    • aop concept
    • spring implements
      • spring-aop
      • spring-aspects
        • xml配置
        • 注解配置

spring-aop 学习记录

面向切面编程aspect oriented programming,实现对现有业务逻辑的非侵入式增强,如日志记录,权限管理的

aop concept
  • join point

    Join point is any point in your program such as method execution, exception handling, field access etc. Spring supports only method execution join point.

    程序中的任意点都可以作为切入点,例如方法执行、异常处理、字段获取……在spring中仅支持在方法执行加入切入点

  • advice

    Advice represents an action taken by an aspect at a particular join point.
    申明表示切面在指定切点发生的动作。

  • pointcut

    It is an expression language of AOP that matches join points.

    在aop中描述切入点

  • introduction

    It means introduction of additional method and fields for a type. It allows you to introduce new interface to any advised object.

    用于解释某种附加方法或字段,这将允许新的接口在任意申明类中被解释

  • target object

    It is the object i.e. being advised by one or more aspects. It is also known as proxied object in spring because Spring AOP is implemented using runtime proxies.

    被切面声明的类。由于spring aop通过动态代理实现,所以spring中通常是代理类

  • aspect

    It is a class that contains advices, joinpoints etc.

    切面包含申明、切入点等信息的类

  • interceptor

    It is an aspect that contains only one advice.

    拦截器是仅持有一个声明的切面

  • aop proxy

    It is used to implement aspect contracts, created by AOP framework. It will be a JDK dynamic proxy or CGLIB proxy in spring framework.

    由aop框架创建,用于实现切面连接。在spirng框架中采用jdk动态代理或cglib代理实现

  • weaving

    It is the process of linking aspect with other application types or objects to create an advised object. Weaving can be done at compile time, load time or runtime. Spring AOP performs weaving at runtime.

    织入是连接切面和其他应用类型或对象主动创建申明对象的过程。织入可能发生在编译、加载或运行期。spring aop织入发生在运行期

spring implements spring-aop

xml配置文件如下


    






    
    
        
            aopAfter
            aopBefore
        
    

关于ProxyFactoryBean中target表示被代理类,interceptorNames为List类型,表示在执行实际方法前经过的拦截器

拦截器定义如下

public class MethodBeforeBean implements MethodBeforeAdvice {
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println("Method name:"+method.getName()+" "+method.getModifiers());
        System.out.println("target object:"+o);

        System.out.println("Before Method exec!");
    }
}

public class MethodAfterBean implements AfterReturningAdvice {
    public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
        System.out.println("After method exec!");
    }
}

调用ProxyFactoryBean生成的代理类,以动态代理的方式实现aop

@Test
public void myFirstTest(){
    ApplicationContext context = new ClassPathXmlApplicationContext("Application.xml");
    SpringTest obj = (SpringTest) context.getBean("aoProxy");
    obj.say();
}

运行结果如下

Method name:say 1
target object:org.miku.bean.SpringTest@291b4bf5
Before Method exec!
real method exec!
After method exec!

spring-aspects

相对于spring-aop代理方式,spring-aspects更加灵活便捷,不再需要为了特定切点而定义不同的类实现不同接口,可以将所有切点动作集中在一个类。

xml配置

spring-aspects可配置的切点时间有

  • aop:before

    被代理方法调用前

  • aop:after

    被代理方法掉用后

  • aop:after-returning

    被代理方法掉用后,常用于对返回值进行拦截

  • aop:around

    被代理方法调用前后

  • aop:after-throwing

    被代理方法抛出异常时

上面这些其实没啥用,实际意思就是字面意思,写上只是为了以后方便找关键字具体执行顺序如下

aop:before exec!
aop:around BEGIN:
real method exec!
aop:after-returning:I Love miku!
aop:around FINISH
aop:after exec!

在了解spring-aspects切点时间之后,接下来就需要考虑如何将切面类配置到动态运行的程序中,首先介绍的方法是在xml文件中进行配置。上一示例的配置文件如下

    
    
        
            
            
            
            
            
        
    

首先在xml文件中配置aop bean。Class#org.miku.bean.AopBean是切面动作的实现类,实现了在具体切点要进行的动作

public class AopBean {

    public void execBefore(){
        System.out.println("aop:before exec!");
    }

    public void execAfter(){
        System.out.println("aop:after exec!");
    }

    public void execAround(ProceedingJoinPoint pj){
        System.out.println("aop:around BEGIN:");

        try {
            pj.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }

        System.out.println("aop:around FINISH");
    }

    public void execAfterReturn(String str){
        System.out.println("aop:after-returning:"+str);
    }
}

之后声明aop执行具体时间,在xml的aop:config标签中配置。
当proxy-target-,表明该aop采用CGLIB实现动态代理,而非java自带代理方式。关于两种代理方式不同,本文暂不过多赘述,重点在于spring aop的使用。
在该配置下随后声明了一个id为aopTest,实现类bean name为AopBeande1切面。在该标签aop:aspect下,将具体方法和执行时间相关联。
首先声明了一个aop:pointcut,没什么特别作用,能少打字。该标签中expression属性指明了切点时间,关于expression中表达式介绍如下:

一个切点表达式以pointcut designator(PCD,本文译为切点指示器)作为起始,以下是几种不同PCD

  • execution

表示切点位于具体方法发生时



如果想要切点在Class#org.miku.bean.SpringTest的所有方法上,可以在表达式中使用通配符



这里要特别指出,由于动态代理实现方式限制(特指java proxies,CGLIB理论可行但不推荐),使用通配符仅能match被代理类的public方法。

  • within

表明切点在类的所有方法上



  • this and target

这俩看不懂,贴个stackoverflow

this(AType) means all join points where this instanceof AType is true. So this means that in your case once the call reaches any method of AccountService this instanceof AccountService will be true.

target(AType) means all join points where anObject instanceof AType . If you are calling a method on an object and that object is an instanceof AccountService, that will be a valid joinpoint.

To summarize a different way - this(AType) is from a receivers perspective, and target(AType) is from a callers perspective.

据说在使用时

The former works when Spring AOP creates a CGLIB-based proxy, and the latter is used when a JDK-based proxy is created.

  • args

这并不是一个新的PCD,而是在使用PCDexecution是利用通配符实现对特定函数名或特定参数类型的筛选






  • @target

这个PCD不同于之前提到过的target PCD,@target表示是否在类上有指定注解。指定注解必须保留到运行期@Retention(RetentionPolicy.RUNTIME)

其余PCD不再一一介绍,反正都差不多,一个execution都能解决,更主要是我懒,详见参考3

一个aop:aspect标签中只能有一个aop:pointcut声明,如果有多个,则仅最先写入pointcut生效

此外expression之间可以用&& || !进行逻辑运算。例如切点在除某方法外,该类的所有方法上:


随后将切面方法于各切点关联,实现切面操作




注解配置

相比xml文件配置,采用注解的方式配置切面更加灵活,示例如下:

@Aspect
public class AopBean {
    @Pointcut("within(org.miku.bean.SpringTest)")
    public void loaction(){}

    @Before("loaction()")
    public void execBefore(){
        System.out.println("aop:before exec!");
    }

    @After("loaction()")
    public String execAfter(){
        System.out.println("aop:after exec!");
        return "at aop after";
    }

    @Around("loaction()")
    public void execAround(ProceedingJoinPoint pj){
        System.out.println("method name is:"+pj.getSignature());
        System.out.println("aop:around BEGIN:");
        Object retVal = null;
        try {
            retVal = pj.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }

        System.out.println("aop:around FINISH");
    }

@Aspect注解声明该类为注解类
@Pointcut标注切点位置
@Before``@After``@Around``@AfterReturning等注解不再一一解释,和xml文件配置差不多。

该切面执行如下

method name is:String org.miku.bean.SpringTest.testReturnString()
aop:around BEGIN:
aop:before exec!
real method exec!
aop:around FINISH
aop:after exec!

注意:Around会拦截method返回值,此时再使用AfterReturning接收不到返回值.

aspect如下:

@Aspect
public class AopBean {
    @Pointcut("within(org.miku.bean.SpringTest)")
    public void loaction(){}

    @Around("loaction()")
    public void execAround(ProceedingJoinPoint pj){
        System.out.println("method name is:"+pj.getSignature());
        try {
            pj.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }

    @AfterReturning(pointcut = "execution(public String org.miku.bean.SpringTest.testReturnString())",
                    returning = "str")
    public void execAfterReturn(JoinPoint jp, String str){
        System.out.println("aop:after-returning:"+str);
    }
}

执行结果如下:

method name is:String org.miku.bean.SpringTest.testReturnString()
real method exec!
aop:after-returning:null

参考文献:

  1. Spring AOP Tutorial
  2. Spring AOP Example
  3. Introduction to Pointcut expressions in Spring
  4. Spring aop multiple pointcuts & advice but only the last one is working
  5. AspectJ pointcut for annotated PRIVATE methods
  6. Spring AOP target() vs this()
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/298733.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

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

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