五Spring-AOP--1基础概念

五Spring-AOP--1基础概念

AOP:面向方面编程。面向方面的编程需要把程序逻辑分解成不同的部分称为所谓的关注点。跨一个应用程序的多个点的功能被称为**横切关注点(把公共逻辑抽离),这些横切关注点在概念上独立于应用程序的业务逻辑。有各种各样的常见的很好的方面的例子,如日志记录、审计、声明式事务、安全性和缓存等。

在 OOP 中,关键单元模块度是类,而在 AOP 中单元模块度是方面。依赖注入IOC帮助你对应用程序对象相互解耦和、AOP 可以帮助你从它们所影响的对象中对横切关注点解耦。

Spring AOP 模块提供拦截器来拦截一个应用程序,例如,当执行一个方法时,你可以在方法执行之前或之后添加额外的功能。

5.0 基础知识

AOP(Aspect Orient Programming),一般称为面向切面编程,作为面向对象的一种补充,用于处理系统中分布于各个模块的横切关注点,比如事务管理、日志、缓存等等。

AOP代理主要分为静态代理动态代理,静态代理的代表为AspectJ;而动态代理则以Spring AOP为代表。静态代理是编译期实现,动态代理是运行期实现,可想而知前者拥有更好的性能。

静态代理
静态代理是编译阶段生成AOP代理类,也就是说生成的字节码就织入了增强后的AOP对象;(并不会创建出多余的对象)

实现方式:
包装器模式:持有目标对象的引用,然后实际上是调用目标对象的方法。   这种方式也可称为代理模式,但是有明显的缺点(比如一般都需要实现同一个接口,且它是以编码的方式去实现的,侵入性高)
AspectJ静态代理方式:非常非常强大。Aspectj并不是动态的在运行时生成代理类,而是在编译的时候就植入代码到class文件。由于是静态织入的,所以性能相对来说比较好。Aspectj不受类的特殊限制,不管方法是private、或者static、或者final的,都可以代理,Aspectj不会代理除了限定方法之外任何其他诸如toString(),clone()等方法,唯一缺点就是必须有AspectJ自己的编译器的支持,所以其实很少使用   Spring也是提供了相关类支持的,比如:LoadTimeWeaverAwareProcessor
 基于AspectJ的静态代理方式非常强大,但是它依赖于它自己的编译器。并且还有自己的个性化语言,使用起来不够方便,因此其实还是使用得较少的。主要还是以动态代理为主~~~
 

动态代理
动态代理则不会修改字节码,而是在内存中临时生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法

这在我们平时使用中得到了大量的使用,因为使用简单并且还非常灵活

为了便于理解AOP中的组件信息,构建如下环境,对springAOP的运行作大致了解

public class Main {

    public static void main(String[] args) {
        ProxyFactory proxyFactory = new ProxyFactory(new Demo());
        proxyFactory.addAdvice((MethodBeforeAdvice) (method, args1, target) ->
                System.out.println("你被拦截了:方法名为:" + method.getName() + " 参数为--" + Arrays.asList(args1)));

        DemoInterface demo = (DemoInterface) proxyFactory.getProxy();
        //你被拦截了:方法名为:hello 参数为--[]
        //this demo show
        demo.hello();

        System.out.println(proxyFactory.getTargetClass()); //class com.fsx.maintest.Demo
        System.out.println(proxyFactory.getTargetSource()); //SingletonTargetSource for target object [com.fsx.maintest.Demo@643b1d11]
        System.out.println(Arrays.asList(proxyFactory.getProxiedInterfaces())); //[interface com.fsx.maintest.DemoInterface]
        System.out.println(Arrays.asList(proxyFactory.getAdvisors())); //[org.springframework.aop.support.DefaultPointcutAdvisor: pointcut [Pointcut.TRUE]; advice [com.fsx.maintest.Main$$Lambda$2/1349414238@2ef5e5e3]]

        // 获取类型,看看是JDK代理还是cglib的
        System.out.println(demo instanceof Proxy); //true  所有的JDK代理都是继承自Proxy的
        System.out.println(demo instanceof SpringProxy); //true
        System.out.println(demo.getClass()); //class com.fsx.maintest.$Proxy0
        System.out.println(Proxy.isProxyClass(demo.getClass())); //true
        System.out.println(AopUtils.isCglibProxy(demo)); //false

        //测试Advised接口、DecoratingProxy的内容
        Advised advised = (Advised) demo;
        System.out.println(Arrays.asList(advised.getProxiedInterfaces())); //[interface com.fsx.maintest.DemoInterface]
        System.out.println(Arrays.asList(advised.getAdvisors())); //[org.springframework.aop.support.DefaultPointcutAdvisor: pointcut [Pointcut.TRUE]; advice [com.fsx.maintest.Main$$Lambda$2/1349414238@2ef5e5e3]]
        System.out.println(advised.isExposeProxy()); //false
        System.out.println(advised.isFrozen()); //false

        //System.out.println(advised.removeAdvice(null));
        DecoratingProxy decoratingProxy = (DecoratingProxy) demo;
        System.out.println(decoratingProxy.getDecoratedClass()); //class com.fsx.maintest.Demo

        System.out.println("-----------------------------------------------------");

        // Object的方法 ==== 所有的Object方法都不会被AOP代理 这点需要注意
        System.out.println(demo.equals(new Object()));
        System.out.println(demo.hashCode());
        System.out.println(demo.getClass());

        // 其余方法都没被拦截  只有toString()被拦截了  咋回事呢?它也不符合切点表达式的要求啊  看下面的解释吧
        // 你被拦截了:方法名为:hello 参数为--[]
        // com.fsx.maintest.Demo@643b1d11
        System.out.println(demo.toString());
    }
}

interface DemoInterface {
    void hello();
}

class Demo implements DemoInterface {
    @Override
    public void hello() {
        System.out.println("this demo show");
    }
}

5.1 AOP基础概念

image-20230310114508923

(1) AOP有关的术语:

img

Aspect:方面。就是对切面进行处理的功能模块,如日志模块

Join point:连接点 。(包括方法表示的程序执行点and用相对点表示的方位)

Advice:通知或增强。就是实际行动之前或之后执行的方法(代码),下面定义了5中通知工作。增强是织入到目标类target的joinpoint上的一段程序代码。

增强包括:一段程序代码and和执行点的方位(after、before)。

因此,结合执行点方位信息和pointcut,可以定位到特定joinpoint。

Pointcut:切点。一个或者多个连接点构成的组。

Introduction:引用。引用允许添加新方法或属性到现有的类中。

Target object:目标对象

Waving:编织。

区别pointcut和joinpoint:

joinpoint是客观存在的,相当于数据库中的数据;而pointcut相当于查询条件。springAOP的规则解析引擎,负责pointcut所设定的查询条件,找到对应的joinpoint。

另外joinpoint还包括方法执行前、后等方位信息的具体程序执行点;而pointcut只负责定位到某个方法上,如果希望定位到具体joinpoint,还需要提供before/after等位置信息。

(2)通知advice类型

img

(3)实现自定义

5.2 spring中基于AOP的xml架构

(一)项目中需要使用aop命名空间标签,需要导入spring-aop架构

(1) Xml的格式

img

(2) 程序的classpath中导入AspectJ库文件

img

(二)声明方面

(1)声明aspect

Aspect使用aop:config这样的元素进行声明。

img

(2)声明切入点

切入点是执行感兴趣的连接点

img

元素pointcut用来设置切入点的匹配规则等。

(3)声明通知 advice

使用 <aop:{ADVICE NAME}> 元素在一个 中声明五个通知类型中的任何一个

img

示例:

(1)切面方法,如beforeadvice、afterdivice等,都统统写在一个java类中,这个类就是Aspect(方面)

img

并且,在XML中,将该类,配置如下

将其配置为aspect方面

img

Ref引用bean,bean是aspect的真实实现类,其中定义了切面方法(也就是增强advice)。

img

(2)XML文件配置

img

注意:

对于after-returning、after-throwing两个通知类型,由于是方法执行后的通知,因此,XML中对应的retval、ex,都对应的是返回的对象的实例。

如,

img

XML中

img

在通知前后,这些retval、ex就指代切点方法的返回值,包括方法的返回值、异常对象实例。

5.3 Spring 中基于 AOP 的 @AspectJ

首先,需要在基于架构XML配置文件中,进行如下配置

img

然后,需要下载相应的AspectJ库文件

img

(1)声明aspect

对类用@Aspect注解

img

然后,在XML中进行配置

img

(2)声明一个切入点

在处理基于配置的 XML 架构时,切入点的声明有两个部分:

定义的切点匹配规则;定义的切点的名称

img

此处,切点名字为businessservice,匹配到的方法为execution内的方法。注意:这是给execution切入点pointcut命名。

(3)声明建议

你可以使用 @{ADVICE-NAME} 注释声明五个建议中的任意一个,如下所示。这假设你已经定义了一个切入点标签方法 businessService()

img

@before(),括号中的businessservice,就是前一步定义的切入点方法别名。

在对pointcut切点对应的方法执行时,before与其操作,执行doBeforeTask的方法。

注意:

由于该过程主要出现了两个java.class,一个是作为aspect(切面处理模块)的类,一个作为切点的目标对象,因此,需要在XML中,对这两个java,配置bean

img

posted @ 2023-03-10 17:10  LeasonXue  阅读(40)  评论(0编辑  收藏  举报