java动态代理

简介: java动态代理

1、引言


最近在看一些技术源码的时候,发现很多地方都是动态代理, 真可谓是一切皆代理啊,所以我们需要弄明白代理模式这样在看源码的时候会好受很多。


2、基本概念


代理(Proxy)模式提供了间接访问目标对象的方式,即通过代理对象访问目标对象,这样做的好处是:可以在目标对象的功能上,增加额外的功能补充,即扩展目标对象的功能。


这就符合了设计模式低开闭原则,即在对既有代码不改动的情况下进行功能扩展。


举个我们平常非常常见的例子, 明星和经纪人就是被代理和代理的关系,明细出演活动的时候,明细就是一个目标对象,他只负责活动中的节目,而其他的琐碎的事情就交给他的代理人(经纪人)来解决。这就是代理思想 中的一个例子。


3、静态代理


静态代理的特点:代理类和目标类必须实现 同一个接口或者继承相同的父类。所以我们需要 定义一个接口。下面来看具体实现demo。


接口类:

/**
 * @author zhenghao
 * @description:
 * @date 2020/12/1410:28
 */
public interface Istart {
    void sing();
}


目标类:

/**
 * @author zhenghao
 * @description:
 * @date 2020/12/1416:07
 */
public class LDHStar implements Istart {
    @Override
    public void sing() {
        System.out.println("华仔唱歌");
    }
}

代理类:

/**
 * @author zhenghao
 * @description:
 * @date 2020/12/1416:08
 */
public class StaticPorxyManager implements Istart {
    private Istart target;
    public StaticPorxyManager(Istart target) {
        this.target = target;
    }
    @Override
    public void sing() {
        System.out.println("演唱会之前。。。。");
        this.target.sing();
        System.out.println("演唱会之后。。。。");
    }
}

测试类:

/**
 * @author zhenghao
 * @description:
 * @date 2020/12/1410:46
 */
public class StaticTeasMain {
    public static void main(String[] args) {
        Istart ldhStar = new LDHStar();
        StaticPorxyManager staticPorxyManager = new StaticPorxyManager(ldhStar);
        staticPorxyManager.sing();
    }
}


静态代理类优缺点:


有点:可以在不修改目标代码的情况下,扩折额外 功能

缺点:因为代理类和目标类必须实现相同的接口,所以会有很多代理类,类太多, 同时,一旦接口增加方法,目标对象很代理对象都需要维护。而动态代理可以解决上面的问题。


4、JDK动态代理


动态代理的主要特点就是能够在程序运行时JVM才为目标对象生成代理对象。


常说的动态代理也叫做JDK 代理也是一种接口代理,之所以叫做接口代理,是因为被代理的对象也就是目标对象必须实现至少一个接口,没有实现接口不能使用这种方式生成代理对象,JDK中生成代理对象的代理类就是Proxy,所在包是java.lang.reflect.


接口:

/**
 * @author zhenghao
 * @description:
 * @date 2020/12/1410:28
 */
public interface Istart {
    void sing();
}

目标类:

/**
 * @author zhenghao
 * @description:
 * @date 2020/12/1410:29
 */
public class WangFengStar implements Istart {
    @Override
    public void sing() {
        System.out.println("汪峰唱歌。。。");
    }
}

InvocationHandler类:

import java.lang.annotation.Target;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
 * @author zhenghao
 * @description:
 * @date 2020/12/1410:32
 */
public class StarInvocationHandler implements InvocationHandler {
    private  Object target;
    public StarInvocationHandler(Object target) {
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("演唱会前工作");
        //调用目标对象的目标方法
        method.invoke(target,args);
        System.out.println("演唱会后工作");
        return null;
    }
}

代理工厂:

import java.lang.reflect.Proxy;
/**
 * @author zhenghao
 * @description:
 * @date 2020/12/1410:30
 */
public class ProxyFactory {
    private Object target;
    private StarInvocationHandler starInvocationHandler;
    public ProxyFactory( Object target) {
        this.target = target;
        this.starInvocationHandler = new StarInvocationHandler(target);
    }
    public Object getProxyObject(){
       return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),starInvocationHandler);
    }
}

测试方法:

public class TeasMain {
    public static void main(String[] args) {
        Istart wangfengStar = new WangFengStar();
        Istart proxyObject = (Istart)new ProxyFactory(wangfengStar).getProxyObject();
        proxyObject.sing();
    }
}

JDK代理方式不需要代理对象实现接口,但是目标对象一定要实现接口,但是我们在项目中有很多需要代理的类并没有实现接口,所以这也算是这种代理方式的一种缺陷。


5、cglib动态代理


如果我们 需要给没有是实现任何接口的目标类生成代理对象,JDK方式是做不到的。这是就可以使用继承目标类以目标对象子类的方式实现代理,这种方法就叫做Cglib代理,也叫做子类代理,他是在内存中构建一个子类对象从而 实现对目标对象功能的扩展。


Cglib是一个强大的高性能代码生成包,他可以在运行期扩展java类和扩展java接口。它广泛的被许多AOP框架使用,例如Sring AOP和synaop,为他们提供方法的intercepion(拦截)


Cglib包的底层是通过使用一个小而快的字节码处理框架ASM来转换字节码并生成新的类。


Cglib子类代理实现方法:


1.需要引入cglib的jar文件 cglib-2.2.2.jar asm-3.3.1.jar,但是Spring的核心包中已经包括了Cglib功能,所以直接引入spring-core-3.2.5.jar即可.

2.引入功能包后,就可以在内存中动态构建子类

3.代理的类不能为final,否则报错

4.目标对象的方法如果为final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法.


目标类:

/**
 * @author zhenghao
 * @description:
 * @date 2020/12/1410:57
 */
public class JieLunStar {
    public void sing(){
        System.out.println("杰伦唱歌");
    }
}

代理工厂:

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
 * @author zhenghao
 * @description:
 * @date 2020/12/1410:58
 */
public class CglibProxyFactory implements MethodInterceptor {
    //维护目标对象
    private Object target;
    public CglibProxyFactory(Object target) {
        this.target = target;
    }
    /**
     * @Description:获得目标类的代理对象
     * @author: zhenghao
     * @date: 2020/12/14 11:02
    */
    public Object getProxyObject(){
        //1、工具类
        Enhancer enhancer = new Enhancer();
        //2、设置父类
        enhancer.setSuperclass(target.getClass());
        //3、设置回调
        enhancer.setCallback(this);
        //4、创建代理类
        Object proxyObject = enhancer.create();
        return proxyObject;
    }
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("演唱会前工作");
        //执行目标对象的目标方法
        method.invoke(target,objects);
        System.out.println("演唱后前工作");
        return null;
    }

测试类:

/**
 * @author zhenghao
 * @description:
 * @date 2020/12/1410:46
 */
public class CglibTeasMain {
    public static void main(String[] args) {
        JieLunStar jieLunStar = new JieLunStar();
        JieLunStar proxyObject = (JieLunStar)new CglibProxyFactory(jieLunStar).getProxyObject();
        proxyObject.sing();
    }
}


到这三种代理方式我们都介绍完了,下面总结一下:

1、如果目标对象实现了接口,我们就采用JDK方式实现动态代理

2、如果目标对象没有实现接口,我们就需要采用cglib方式实现动态代理;


6、目标是接口+注解的动态代理


注解类:


/**
 * @author zhenghao
 * @description:
 * @date 2020/12/1411:33
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Select {
    String value() default "";
}

目标类:

/**
 * @author zhenghao
 * @description:
 * @date 2020/12/1411:32
 */
public interface IUserDao {
    @Select("select * from user")
    String getUser();
}

InvocationHandler类:

/**
 * @author zhenghao
 * @description:
 * @date 2020/12/1410:32
 */
public class UserInvocationHandler implements InvocationHandler {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //创建类的是一个具体的实现类
        if (Object.class.equals(method.getDeclaringClass())){
            return method.invoke(this,args);
        }else {
            //得到所有注解
            String value = method.getAnnotation(Select.class).value();
            System.out.println("接口上面的注解的内容:" + value);
            //实现具体的业务逻辑 如远程http调用实现等
            return "user info";
        }
    }
}

代理工厂:

import java.lang.reflect.Proxy;
/**
 * @author zhenghao
 * @description:
 * @date 2020/12/1411:47
 */
public class InterfaceProxyFactory  {
    private  Class<?> target;
    private UserInvocationHandler userInvocationHandler;
    public InterfaceProxyFactory( Class<?> target) {
        this.target = target;
        this.userInvocationHandler = new UserInvocationHandler();
    }
    public Object getProxyObject(){
        return Proxy.newProxyInstance(target.getClassLoader(),new  Class[]{target},userInvocationHandler);
    }
}

测试类:

/**
 * @author zhenghao
 * @description:
 * @date 2020/12/1410:46
 */
public class InterfaceProxyTeasMain {
    public static void main(String[] args) {
        IUserDao proxyObject = (IUserDao) new InterfaceProxyFactory(IUserDao.class).getProxyObject();
        System.out.println(proxyObject.getUser());
    }
}


目录
相关文章
|
26天前
|
Java
JAVA 静态代理 & 动态代理
【11月更文挑战第14天】静态代理是一种简单的代理模式实现,其中代理类和被代理类的关系在编译时已确定。代理类实现与被代理类相同的接口,并持有被代理类的实例,通过调用其方法实现功能增强。优点包括代码结构清晰,易于理解和实现;缺点是对于多个被代理类,需为每个类编写相应的代理类,导致代码量大增,维护成本高。动态代理则在运行时动态生成代理类,更加灵活,减少了代码冗余,但可能引入性能损耗和兼容性问题。
|
2月前
|
设计模式 Java API
[Java]静态代理与动态代理(基于JDK1.8)
本文介绍了代理模式及其分类,包括静态代理和动态代理。静态代理分为面向接口和面向继承两种形式,分别通过手动创建代理类实现;动态代理则利用反射技术,在运行时动态创建代理对象,分为JDK动态代理和Cglib动态代理。文中通过具体代码示例详细讲解了各种代理模式的实现方式和应用场景。
31 0
[Java]静态代理与动态代理(基于JDK1.8)
|
2月前
|
Java
深入理解Java动态代理
深入理解Java动态代理
91 1
|
2月前
|
Java
Java代码解释静态代理和动态代理的区别
### 静态代理与动态代理简介 **静态代理**:代理类在编译时已确定,目标对象和代理对象都实现同一接口。代理类包含对目标对象的引用,并在调用方法时添加额外操作。 **动态代理**:利用Java反射机制在运行时生成代理类,更加灵活。通过`Proxy`类和`InvocationHandler`接口实现,无需提前知道接口的具体实现细节。 示例代码展示了两种代理方式的实现,静态代理需要手动创建代理对象,而动态代理通过反射机制自动创建。
|
2月前
|
设计模式 缓存 Java
从源码学习Java动态代理|8月更文挑战
从源码学习Java动态代理|8月更文挑战
|
5月前
|
缓存 Java 测试技术
day27:Java零基础 - 动态代理
【7月更文挑战第27天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
43 2
day27:Java零基础 - 动态代理
|
4月前
|
开发者 C# 容器
【独家揭秘】当WPF邂逅DirectX:看这两个技术如何联手打造令人惊艳的高性能图形渲染体验,从环境搭建到代码实践,一步步教你成为图形编程高手
【8月更文挑战第31天】本文通过代码示例详细介绍了如何在WPF应用中集成DirectX以实现高性能图形渲染。首先创建WPF项目并使用SharpDX作为桥梁,然后在XAML中定义承载DirectX内容的容器。接着,通过C#代码初始化DirectX环境,设置渲染逻辑,并在WPF窗口中绘制图形。此方法适用于从简单2D到复杂3D场景的各种图形处理需求,为WPF开发者提供了高性能图形渲染的技术支持和实践指导。
276 0
|
4月前
|
设计模式 Java C++
揭秘!JDK动态代理VS CGLIB:一场关于Java代理界的‘宫心计’,你站哪队?
【8月更文挑战第24天】Java 动态代理是一种设计模式,允许在不改动原类的基础上通过代理类扩展功能。主要实现方式包括 JDK 动态代理和 CGLIB。前者基于接口,利用反射机制在运行时创建代理类;后者采用继承方式并通过字节码技术生成子类实现类的代理。两者在实现机制、性能及适用场景上有明显差异。JDK 动态代理适用于有接口的场景,而 CGLIB 更适合代理未实现接口的类,尽管性能更优但存在一些限制。开发者可根据需求选择合适的代理方式。
201 0
|
5月前
|
开发框架 Java Android开发
Java中的类反射与动态代理详解
Java中的类反射与动态代理详解
|
5月前
|
Java 数据安全/隐私保护
Java中的动态代理机制详解
Java中的动态代理机制详解