逆水行舟 —— jdk动态代理和Cglib字节码增强

JDK动态代理

利用拦截器加上反射机制生成一个实现代理接口的匿名类,在调用具体方法时,调用InvocationHandler来处理

JDK动态代理只需要JDK环境就可以进行代理,流程为:

  1. 实现InvocationHandler
  2. 使用Proxy.newProxyInstance产生代理对象
  3. 被代理的对象必须实现接口

具体列子如下:

public class UserServiceImpl implements UserService {

    @Override
    public void eat() {
        System.out.println("---------吃饭");
    }
    @Override
    public void wc() {
        System.out.print("上茅房------>");
    }
}
//切面类
public class MyAspect {

    public void before(){
        System.out.print("先洗手再");
    }

    public void after(){
        System.out.print("后要洗手");
    }
}
// 产生代理对象的工厂类
public class MyFactoryBean {

    public static UserService getInstance(){
        // target : 目标类
        final UserService service = new UserServiceImpl();
        // Aspect : 切面类
        final MyAspect aspect = new MyAspect();
        // Weaving : 织入,也就是产生代理的过程
        UserService proxy = (UserService) Proxy.newProxyInstance(
                MyFactoryBean.class.getClassLoader(),
                new Class[]{UserService.class},
                new InvocationHandler(){
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        if (method.getName().equals("eat")){
                            aspect.before();
                        }
                        Object invoke = method.invoke(service, args);
                        if (method.getName().equals("wc")){
                            aspect.after();
                        }
                        return invoke;
                    }
                });
        return proxy;
    }
}
//测试方法
@Test
public void userTest(){
    UserService userService = MyFactoryBean.getInstance();  //使用工厂类产出代理对象
    userService.eat();
    userService.wc();
}

效果如下:

CGLIB动态代理

  1. 通过加载对象类的class文件,修改其字节码生成子类的方式完成,不需要实现接口
  2. 但是需要第三方库:CGLIB类库的支持
public class MyProxy implements MethodInterceptor {
?
    private Object personService;

    public Object createProxy(Object obj){
        this.personService = obj;
        Enhancer e = new Enhancer();
        e.setSuperclass(obj.getClass());
        e.setCallback(this);
        Object proxy = e.create();
        return proxy;   //返回代理对象
    }
?
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        Object obj = null;
        if ("eat".equals(method.getName())){
            System.out.print("先洗手再----->");
        }
?
        obj = method.invoke(personService, objects);

        if ("wc".equals(method.getName())){
            System.out.print("---->之后要洗手");
        }
        return obj;
    }
}
public class PeopleService {    public void eat(){        System.out.println("吃饭");    }    public void wc(){        System.out.print("上厕所");    }}
@Test
public void Test1(){
    MyProxy myProxy = new MyProxy();
    PeopleService proxy =(PeopleService) myProxy.createProxy(new PeopleService());
    proxy.eat();
  

效果如下:

      

总结

关于在Spring的AOP中采用何种代理手段,我们不强加限制的话,会根据类是否有接口来区别对待

  1. 当一个类有接口的时候,就会选用JDK的动态代理
  2. 当一个类没有实现接口的时候,就会选用CGLIB代理的方式

两种代理方式的本质:

  1. JDK动态代理是针对实现了接口的类生成代理,不是针对类
  2. CGLIB使用的是为被代理类生成一个子类,通过继承的方法覆盖并增强其方法,

    但是因为是继承所以不能声明被代理类为final,无法被继承无法实现CGLIB代理

原文地址:https://www.cnblogs.com/msi-chen/p/10801816.html

时间: 2024-11-05 22:00:38

逆水行舟 —— jdk动态代理和Cglib字节码增强的相关文章

JDK动态代理和CGLIB的区别

Aspect默认情况下不用实现接口,但对于目标对象,在默认情况下必须实现接口 如果没有实现接口必须引入CGLIB库 我们可以通过Advice中添加一个JoinPoint参数,这个值会由spring自动传入,从JoinPoint中可以取得 参数值.方法名等等 1.如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP 2.如果目标对象实现了接口,可以强制使用CGLIB实现AOP 3.如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换

JDK动态代理和CGLIB代理的区别

一.原理区别: java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理. 而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理. 1.如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP 2.如果目标对象实现了接口,可以强制使用CGLIB实现AOP 3.如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换 如何强制使用

JDK动态代理和CGLIB动态代理+源码下载

在上一篇文章-java代理详解讲解实现机制,一种是继承另外一种是组合,而且通过做实现也证明使用组合的方式更加的灵活.之后提到了代理的两种种类,一种是静态代理,另外一种是动态代理.上一篇文件中着重介绍的是静态代理(相对于动态代理很容易理解).这一片文章就接着介绍动态代理. 动态代理实现的最终效果:通过以一个统一的方式实现对任意的接口/类的代理.相比较静态代理而言,我们可以不用再无限制的增加代理类,不用再写许多重复的代码.很符合面向对象设计原则中的"开闭原则":对修改关闭,对扩展开放. 动

JDK动态代理和CGLIB动态代理

转载自http://www.itzhai.com/java-dong-tai-dai-li-zhi-jdk-dong-tai-dai-li-he-cglib-dong-tai-dai-li-mian-xiang-qie-mian-bian-cheng-aop-yuan-li.html 静态代理 静态代理相对来说比较简单,无非就是聚合+多态: 参考:设计模式笔记 – Proxy 代理模式 (Design Pattern) 动态代理 我们知道,通过使用代理,可以在被代理的类的方法的前后添加一些处理方

spring aop原理 JDK动态代理和CGLIB动态代理

Spring的两大特性是IOC和AOPIOC负责将对象动态的注入到容器,从而达到一种需要谁就注入谁,什么时候需要就什么时候注入的效果.理解spring的ioc也很重要.但是今天主要来和大家讲讲aop.AOP 广泛应用于处理一些具有横切性质的系统级服务,AOP 的出现是对 OOP 的良好补充,用于处理系统中分布于各个模块的横切关注点,比如事务管理.日志.缓存等等. AOP实现的关键在于AOP框架自动创建的AOP代理.AOP代理主要分为静态代理和动态代理, 静态代理的代表为AspectJ:动态代理则

设计模式---JDK动态代理和CGLIB代理

Cglig代理设计模式 /*测试类*/ package cglibProxy; import org.junit.Test; public class TestCglib { @Test public void test1(){ CglibProxy cglibProxy=new CglibProxy(); UserServiceImpl userServiceImpl = (UserServiceImpl)cglibProxy.createProxyInstance(new UserServi

jdk动态代理和cglib动态代理底层实现原理详细解析(cglib动态代理篇)

代理模式是一种很常见的模式,关于底层原理网上看到很多的有关的讲解,但看了一些都觉得比较粗略,很多时候把底层代码copy下来也不大讲解,感觉不如自己详细的写上一篇.本文将以非常详细的说明来分析cglib动态代理底层的实现原理,篇幅较长,但是每个核心方法代码中每步都有说明.还请耐心阅读 1. 举例 使用cglib代理需要引入两个包,maven的话包引入如下 <!-- https://mvnrepository.com/artifact/cglib/cglib --> <dependency&

深入探索spring技术内幕(六): JDK动态代理和cglib生成代理

[ JDK生成代理 ] JDK中给我们提供了一个Proxy类可以动态的给我们生成代理. 假定我们要做一个权限管理系统, 需要控制用户对某一个方法的访问. 如果user为null, 那么不让用户访问save方法. ① 接口类: PersonService public interface PersonService { public void save(); } ② 实现类: PersonServiceImpl public class PersonServiceImpl implements P

关于JDK动态代理和CGLIB动态代理

1. 代理模式 一句话总结:为其他对象提供一种代理以控制对这个对象的访问.千篇一律的介绍:代理模式是常用的java设计模式,他的特征是代理类与委托类(或目标类)有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务. 按照代理的创建时期,代理类可以分为两种. 静态代理:由程序员创建或特定工具