AOP实现(JDK动态代理和CGlib动态代理)

AOP实现方式:JDK与CGlib动态代理解析
文章介绍了AOP的实现方式,包括ajc编译器、JDK动态代理和CGlib动态代理。JDK动态代理适用于目标对象实现接口的情况,代理对象和目标对象是兄弟关系。而CGlib动态代理则是通过子类化目标对象来实现,适用于未实现接口的目标对象,但不能代理final方法。Spring框架中两种方式都有使用。

AOP(面向切面编程)的实现方式有多种,

  1. ajc编译器:可以通过aspectj-maven-plugin插件在编译期对原java文件的字节码进行修改。
  2. agent类加载:在类加载时完成方法增强,通过设置JVM参数-javaagent:C:/Users/manyh/.m2/repository/org/aspectj/aspectjweaver/1.9.7/aspectjweaver-1.9.7.jar完成,其中C:/Users/manyh/.m2/repository是本地maven仓库的地址
  3. JDK动态代理,JDK支持的动态代理方式
  4. cglib动态代理,spring提供的动态代理方式

主要介绍一下JDK动态代理CGlib动态代理,这两种方式也是Spring框架中使用的方式

JDK动态代理

特点:

  • 1、目标对象和代理对象间是兄弟关系,都实现同一个接口
  • 2、目标类可以修饰final关键字,不影响代理类的增强
public class JdkProxyDemo {

    interface Foo {
        void foo();
    }

    static class Target implements Foo {

        @Override
        public void foo() {
            System.out.println("target foo");
        }
    }

    // jdk 只能针对接口代理
    // cglib
    public static void main(String[] args) {
        // 目标对象
        Target target = new Target();

        // 用来加载在运行期间动态生成的字节码
        ClassLoader classLoader = JdkProxyDemo.class.getClassLoader();
        // 代理对象
        Foo proxy = (Foo) Proxy.newProxyInstance(classLoader, new Class[]{Foo.class}, (p, method, args1) -> {
            System.out.println("before...");
            // 通过反射调用method:方法.invoke(目标, 参数);
            Object result = method.invoke(target, args1);
            System.out.println("after...");
            // 让代理也返回目标方法执行的结果
            return result;
        });
        proxy.foo();
    }
}

cglib动态代理

特点:

  • 目标对象和代理对象间是父子关系,代理类继承目标类
  • 目标类加final关键字时会报错;目标类中的方法加了final关键字虽然不会报错,但不会被代理增强
  • 代理对象是通过方法重写完成的增强(静态方法不能被重写,同样也不能被增强)
public class CglibProxyDemo {

    static class Target {

        public void foo() {
            System.out.println("target foo");
        }
    }

    // cglib:代理是字类型,目标是父类型
    public static void main(String[] args) {
        Target target = new Target();

        Target proxy = (Target) Enhancer.create(Target.class, new MethodInterceptor() {
            /**
             *
             * @param o 代理类自己
             * @param method 当前执行的方法
             * @param args1 方法的执行参数
             * @param methodProxy 方法。。。。
             * @return
             * @throws Throwable
             */
            @Override
            public Object intercept(Object o, Method method, Object[] args1, MethodProxy methodProxy) throws Throwable {
                System.out.println("before...");
                // 通过反射调用method:方法.invoke(目标, 参数);
                // Object result = method.invoke(target, args1);
                // methodProxy 它可以避免反射调用
                Object result = methodProxy.invoke(target, args1);// 内部没有用反射,Spring 使用的是这种
                // invokeSuper方法的参数第一个参数只需要传入代理对象,不需要目标对象
                // Object result = methodProxy.invokeSuper(o, args1);// 内部没有用反射
                System.out.println("after...");
                return result;
            }
        });

        proxy.foo();
    }
}
### JDK 动态代理示例 JDK 动态代理基于接口实现。首先定义一个接口实现类: ```java // 定义接口 interface UserService { void saveUser(); } // 实现接口 class UserServiceImpl implements UserService { @Override public void saveUser() { System.out.println("Saving user..."); } } ``` 接着创建一个 `InvocationHandler` 实现类来处理代理逻辑: ```java import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; class UserServiceInvocationHandler implements InvocationHandler { private final Object target; UserServiceInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Before saving user..."); Object result = method.invoke(target, args); System.out.println("After saving user..."); return result; } } ``` 最后在 Spring Boot 中使用 JDK 动态代理: ```java import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class JdkProxyExample implements CommandLineRunner { public static void main(String[] args) { SpringApplication.run(JdkProxyExample.class, args); } @Override public void run(String... args) throws Exception { UserService userService = new UserServiceImpl(); UserServiceInvocationHandler handler = new UserServiceInvocationHandler(userService); UserService proxy = (UserService) Proxy.newProxyInstance( userService.getClass().getClassLoader(), userService.getClass().getInterfaces(), handler ); proxy.saveUser(); } } ``` 在这个示例中,JDK 动态代理通过 `Proxy.newProxyInstance` 方法为 `UserService` 接口创建了代理对象,在调用 `saveUser` 方法前后添加了额外的逻辑[^1]。 ### CGLIB 代理示例 CGLIB 代理是通过生成目标类的子类来实现的。首先定义一个普通类: ```java class ProductService { public void addProduct() { System.out.println("Adding product..."); } } ``` 然后创建一个 `MethodInterceptor` 实现类来处理代理逻辑: ```java import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; class ProductServiceInterceptor implements MethodInterceptor { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("Before adding product..."); Object result = proxy.invokeSuper(obj, args); System.out.println("After adding product..."); return result; } } ``` 最后在 Spring Boot 中使用 CGLIB 代理: ```java import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class CglibProxyExample implements CommandLineRunner { public static void main(String[] args) { SpringApplication.run(CglibProxyExample.class, args); } @Override public void run(String... args) throws Exception { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(ProductService.class); enhancer.setCallback(new ProductServiceInterceptor()); ProductService proxy = (ProductService) enhancer.create(); proxy.addProduct(); } } ``` 在这个示例中,CGLIB 代理通过 `Enhancer` 类为 `ProductService` 类创建了代理对象,在调用 `addProduct` 方法前后添加了额外的逻辑[^1]。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值