动态代理之JDK原生代理和cglib代理区别
JDK代理实现
1,首先要实现JDK代理的先决条件为,代理类和目标类要实现相同的接口!!!这一点非常重要
JDK代理实现步骤:
(1)实现接口
定义需要代理的方法
public interface House {
/**
* 租房*/
void rent();
}
(2)定义目标类
必须实现上面的接口
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Renter implements House{
private String name;
@Override
public void rent() {
System.err.println(name+"租到了房子……");
}
}
(3)基于jdk代理实现动态代理(动态生成代理类)
代码-固定,需要改变就是代理方法的增强
public class JdkProxy implements InvocationHandler {
/**目标类对象*/
private Object target;
public JdkProxy(Object obj){
this.target=obj;
}
/**
* 1.代理的方法
* 参数说明:
* 1.proxy 代理对象
* 2.method 代理的方法对象
* 3.args 原方法的参数对象*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.err.println("我是中介,我来!");
//执行原方法-目标类中的方法
Object obj=method.invoke(target,args);
System.err.println("我中介,租房任务完成!");
return obj;
}
/**
* 2.定义方法 实现代理类的生成*/
public Object createProxy(){
/*
* 创建代理对象
* 参数说明:
* 1.类加载器
* 2.目标类实现的接口
* 3.InvocationHandler 接口的对象 方法增强的实现*/
Object proxy=Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
this);
return proxy;
}
}
(4)测试运行
@Test
public void t1(){
//1.目标类
Renter renter = new Renter("siri");
//2.生成代理类
House house = (House) new JdkProxy(renter).createProxy();
//3.执行租房方法
house.rent();
}
(5)执行结果
JDK代理的特点:
1.目标类 需要实现接口
2.目标类和代理类不能互相转换(代理类和目标类只是实现了相同的接口,但并没有直接关系)
问题,目标类没有实现接口,怎么办
这就需要cglib代理来干活了
Cglib代理
Cglib代理:CGLIB(Code Generation Library)是一个开源项目。
是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口
Cglib代理不对目标类有任何要求,可以直接实现目标类中的方法增强
Cglib代理实现步骤:
(1)依赖jar
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
(2)定义目标类
@Data
public class Staff {
private String name;
public void run(){
System.err.println(name+"正在参加100米挑战赛!");
}
}
(3)编写cglib代码
public class CglibProxy implements MethodInterceptor {
/**
* 1.代理类的方法 增强的处理
* 参数说明:
* 1.代理类对象
* 2.目标方法
* 3.目标方法的参数
* 4.代理类中的目标方法*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//增强的处理
// if(methodProxy.getSuperName().equals("run")) {
// }
System.err.println("加油!");
//执行原方法 不要写错了 run
Object obj = methodProxy.invokeSuper(o, objects);
return obj;
}
/**
* 2.生成代理类对象*/
public <T> T createProxy(Class<T> target){
Enhancer enhancer=new Enhancer();
//代理类 继承的目标类☆☆☆☆☆
enhancer.setSuperclass(target);
//设置增强的方法 MethodInterceptor对象
enhancer.setCallback(this);
return (T)enhancer.create();
}
}
(4)运行测试
@Test
public void t1(){
//获取代理类对象 代理类继承目标类 代理目标中所有的方法
Staff staff=new CglibProxy().createProxy(Staff.class);
staff.setName("张三");
staff.run();
}
(5)结果
这里增强方法被执行了两次是因为,Staff类中的所有方法都被增强了,当然包括 staff.setName(“张三”)方法。
Cglib代理的特点:
1.代理类基层目标类
2.对目标类没有要求
JDK代理 VS Cglib代理
区别 | jdk代理 | Cglib代理 |
---|---|---|
目标类 | 必须实现接口 | 没有要求 |
代理类 | 代理类和目标类 实现相同的接口 | 代理类继承目标类 |
区别 | jdk代理 | Cglib代理 |
---|---|---|
目标类 | 必须实现接口 | 没有要求 |
代理类 | 代理类和目标类 实现相同的接口 | 代理类继承目标类 |