String AOP 实现原理

 String AOP 实现原理

Spring AOP 是构建在动态代理基础上,因此 Spring 对 AOP 的⽀持局限于⽅法级别的拦截。

Spring AOP ⽀持 JDK Proxy 和 CGLIB ⽅式实现动态代理。默认情况下,实现了接⼝的类,使⽤ AOP 会基于 JDK ⽣成代理类,没有实现接⼝的类,会基于 CGLIB ⽣成代理类

spring的切面由包裹222了目标对象的代理类实现,代理类实现处理方法的调用,执行额外的切面逻辑,并调用目标方法。

1.1 织⼊(Weaving):代理的⽣成时机

织⼊是把切⾯应⽤到⽬标对象并创建新的代理对象的过程,切⾯在指定的连接点被织⼊到⽬标对象中。

在⽬标对象的⽣命周期⾥有多个点可以进⾏织⼊:

编译期:

切面在目标类编程时被织入,需要特殊编译器,AspectJ的织入编译器就是以此方式织入切面。

类加载期:

切面在目标类加载到JVM时被织入,这种方式需要特殊的类加载器(ClassLoader),它可以在目标类被引入应用之前增强该目标类的字节码,AspectJ5的加载时织入,(Load-time weaving.LTW)就支持该方式织入切面。

运行期:

切面在应用运行的某个时刻被织入,一般织入切面时,AOP容器会为目标对象动态创建一个代理对象,SpringAOP就是该方式织入切面。

1.2 动态代理

动态代理通常是在运行时利用 Java 反射机制动态地生成一个代理类,该代理类在运行时织入字节码来完成额外的逻辑,而不是通过修改源代码进行编译期织入。

具体说:动态代理会创建一个实现特定接口的代理对象,在代理对象的方法调用时,会使用反射机制调用原始对象的方法,并在方法调用前后执行其他逻辑。 这个过程中,代理对象的字节码是在运行时生成,并动态织入了额外的字节码。

这种动态代理的实现方式可以帮助我们在运行期间为对象添加新的行为,而不需要修改对象的源代码。这是 AOP(面向切面编程)等技术实现的基础。

1.3 AOP的支持方式

Spring 框架中的AOP,主要基于两种⽅式:JDK 及 CGLIB 的⽅式。这两种⽅式的代理⽬标都是被代理类中的⽅法,在运⾏期,动态的织⼊字节码⽣成代理类。

CGLIB是Java中的动态代理框架,主要作⽤就是根据⽬标类和⽅法,动态⽣成代理类。

Java中的动态代理框架,⼏乎都是依赖字节码框架(如 ASM,Javassist 等)实现的。

字节码框架是直接操作 class 字节码的框架。可以加载已有的class字节码⽂件信息,修改部分信息,或动态⽣成⼀个 class。

JDK 动态代理实现:

JDK 实现时,先通过实现 InvocationHandler 接⼝创建⽅法调⽤处理器,再通过 Proxy 来创建代理类:

//JDK动态代理的实现
//动态代理:使⽤JDK提供的api(InvocationHandler、Proxy实现),此种⽅式实现,要求被
//代理类必须实现接⼝
public class PayServiceJDKInvocationHandler implements InvocationHandler {

    //目标对象就是被代理对象
    private Object target;

    public PayServiceJDKInvocationHandler(Object target){
        this.target=target;
    }
    //proxy代理对象
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //1.安全检查
        System.out.println("安全检查");
        //2.记录日志
        System.out.println("记录日志");
        //3.时间统计开始
        System.out.println("记录开始时间");
        //通过反射调用被代理类的方法
        Object retVal=method.invoke(target,args);
        //4.时间统计结束
        System.out.println("记录结束时间");
        return retVal;
    }

    public static void main(String[] args) {
        PayService target= new AliPayService();
            //⽅法调⽤处理器
        InvocationHandler handler =
                new PayServiceJDKInvocationHandler(target);
            //创建⼀个代理类:通过被代理类、被代理实现的接⼝、⽅法调⽤处理器来创建
        PayService proxy = (PayService) Proxy.newProxyInstance(target.getClass().getClassLoader(),
                new Class[]{PayService.class},handler);
        proxy.pay();
    }
}

CGLIB 动态代理实现

public class PayServiceCGLIBInterceptor  implements MethodInterceptor {
    //被代理对象
    private Object target;
    public PayServiceCGLIBInterceptor(Object target){
        this.target=target;
    }
    @Override
   public Object intercept(Object o, Method method, Object []args, MethodProxy methodProxy) throws Throwable
    {
        //1.安全检查
        System.out.println("安全检查");
        //2.记录日志
        System.out.println("记录日志");
        //3.时间统计开始
        System.out.println("记录开始时间");
        //通过cglib的代理方法调用
        Object retVal=methodProxy.invoke(target,args);
        //4.时间统计结束
        System.out.println("记录结束时间");
        return retVal;
    }

    public static void main(String[] args) {
        PayService target= new AliPayService();
        PayService proxy=(PayService) Enhancer.create(target.getClass(),n
                ew PayServiceCGLIBInterceptor(target));
        proxy.pay();
    }
}

1.4 JDK 和 CGLIB 实现的区别

1. JDK 实现:

要求被代理类必须实现接⼝,之后是通过 InvocationHandler 及 Proxy,在运⾏时动态的在内存中⽣成了代理类对象,该代理对象是通过实现同样的接⼝实现(类似静态代理接⼝实现的⽅式),只是该代理类是在运⾏期时,动态的织⼊统⼀的业务逻辑字节码来完成。

2. CGLIB 实现:

被代理类可以不实现接⼝,是通过继承被代理类,在运⾏时动态的⽣成代理类对象。

a.出身不同

b.实现不同:

JDK Proxy要求代理类实现接口才能实现代理;CGLIB是通过实现代理类的子类完成动态代理。

c.性能不同:

JDK 7+ JDK Proxy性能略高于CGLIB ;JDK 7之前CGLIB性能原因高于JDK Proxy

总结:

AOP 是对某⽅⾯能⼒的统⼀实现,它是⼀种实现思想,Spring AOP 是对 AOP 的具体实现,SpringAOP 可通过 AspectJ(注解)的⽅式来实现 AOP 的功能,Spring AOP 的实现步骤是:1. 添加 AOP 框架⽀持。2. 定义切⾯和切点。3. 定义通知。Spring AOP 是通过动态代理的⽅式,在运⾏期将 AOP 代码织⼊到程序中的,它的实现⽅式有两种:JDK Proxy 和 CGLIB

  • 21
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
AOP(Aspect-Oriented Programming)是一种编程思想,主要用于解决横切关注点(Crosscutting Concerns)的问题。横切关注点指的是那些影响系统多个部分的问题,比如日志、事务、安全等。 AOP 通过在程序中定义切面(Aspect),将横切关注点与业务逻辑分离开来,从而提高代码的可维护性和可重用性。 在 Java 中,AOP 可以使用 AspectJ 等工具实现。 以下是一个使用 AspectJ 实现 AOP 的示例: 首先,定义一个日志切面 LogAspect: ```java import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; @Aspect public class LogAspect { @Before("execution(* com.example.service..*.*(..))") public void logBefore(JoinPoint joinPoint) { System.out.println("Before " + joinPoint.getSignature().getName() + " method"); } @AfterReturning(pointcut = "execution(* com.example.service..*.*(..))", returning = "result") public void logAfterReturning(JoinPoint joinPoint, Object result) { System.out.println("After " + joinPoint.getSignature().getName() + " method"); System.out.println("Result: " + result); } } ``` 上面的代码定义了一个切面 LogAspect,它包含两个通知(Advice): - logBefore:在执行 com.example.service 包中的所有方法之前打印日志; - logAfterReturning:在执行 com.example.service 包中的所有方法之后打印日志和返回值。 然后,在 Spring 配置文件中配置 AspectJ 自动代理: ```xml <aop:aspectj-autoproxy/> <bean id="logAspect" class="com.example.aspect.LogAspect"/> ``` 最后,在业务逻辑类中使用 @Service 注解并调用方法: ```java @Service public class UserService { public String getName() { return "Alice"; } } ``` 当调用 UserService.getName() 方法时,LogAspect 中定义的通知会自动被触发,打印出以下信息: ``` Before getName method After getName method Result: Alice ``` 这就是 AOP 的基本使用方法和原理。通过定义切面和通知,我们可以将横切关注点与业务逻辑分离开来,提高代码的可维护性和可重用性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值