JAVA动态代理详解
问题
1:什么是静态代理,动态代理?
2:动态代理的好处?
什么是静态代理
以生活中例子来看,我作为某某品牌面膜的北京区代理,我替厂家卖面膜,我属于代理,厂家属于委托方。
联系到JAVA中就是,我作为一个代理类,我替委托类去调用方法,同时可以添加一些附加的功能。
如果一个代理类在程序运行之前就已经存在了,那么这种代理方式被称为静态代理。
先上代码
父接口:
public interface Person {
/**
* 吃饭
*/
void eat();
/**
* 拉稀
*/
void shit();
}
委托类:
class Zhangsan implements Person{
@Override
public void eat() {
System.out.println("我每天都会吃饭;");
}
@Override
public void shit() {
System.out.println("我偶尔会拉稀;");
}
}
静态代理类:
class DynamicPerson implements Person{
/**
* 委托类
*/
private Zhangsan zhangsan;
@Override
public void eat() {
System.out.println("附加功能");
zhangsan.eat();
}
@Override
public void shit() {
}
}
由上代码可知,代理类中将委托类引入了进来,但是怎么保证代理类的方法列表和委托类的方法列表一致呢,这里是通过接口约束了方法列表。
静态代理的弊端:对于委托类的每一个方法,都得重新编辑同时加入自己的附加功能,委托类方法过多时,效率太低。
动态代理引入
动态代理的引入就是在静态代理的基础上,添加了一个中间处理类,当调用委托类的方法时,优先进入中间处理类,自定义的附加功能放在中间处理类中即可。
动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类的函数。
中间处理类:
class Handle implements InvocationHandler {
/**
* 委托类
*/
private Object obj;
/**
* 构造方法
* @param obj 委托类对象
*/
public Handle(Object obj){
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//自定义添加内容
System.out.println("我每天先刷牙;");
//调用委托类的方法
Object result = method.invoke(obj, args);
return result;
}
测试类:
public static void main(String[] args) {
//获取中间处理类
Handle handle = new Handle(new Zhangsan());
//获取动态代理实例 向上转型
Person person = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(), new Class[]{Person.class}, handle);
person.shit();
}
测试结果:
我每天先刷牙;
我偶尔会拉稀;
Process finished with exit code 0
注意点
方法内部调用方法的情况:
class Zhangsan implements Person{
@Override
public void eat() {
System.out.println("我每天都会吃饭;");
}
@Override
public void shit() {
System.out.println("我偶尔会拉稀;");
}
@Override
public void eatAndShit() {
eat();
shit();
}
}
输出结果:
我每天先刷牙;
我每天都会吃饭;
我偶尔会拉稀;
Process finished with exit code 0
对于委托类方法中的嵌套方法调用,是走方法内部调用,没有代理对象
动态代理分类
那么在Spirng当中动态代理有两种
-
第一种是JDK自带的动态代理
动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理. 需要指定一个类加载器,然后生成的代理对象实现类的接口或类的类型,接着处理额外功能. JDK是基于接口 -
第二种是Cglib的动态代理
是动态代理利用asm的开源包,对代理对象的Class文件加载进来,通过修改其字节码生成的子类来处理 Cglib是基于继承父类生成的代理类.
两种代理方式的区别:
-
1:JDK动态代理制能对实现了接口的类生成代理,而不是针对类
-
2:CGLIB是针对类实现代理,主要对指定的类生成一个子类,覆盖其中的方法,添加额外功能,因为是继承,所以该类方法不能用final来声明.
对于具体CHLIB的代码示例参考:
/qq_42807370/article/details/87354522