一、代理基础
1.1 什么是动态代理
代理: 使用jdk的反射机制,创建对象的能力, 创建的是代理类的对象。 而不用你创建类文件。不用写java文件。
动态:在程序执行时,调用jdk提供的方法才能创建代理类的对象。
jdk动态代理,必须有接口,目标类必须实现接口, 没有接口时,需要使用cglib 动态代理
1.2 动态代理作用
- 功能增强: 在你原有的功能上,增加了额外的功能。 新增加的功能,叫做功能增强。
- 控制访问: 代理类不让你访问目标,例如商家不让用户访问厂家。
1.3 代理的实现方式
1.3.1 静态代理
- 代理类是自己手工实现的,自己创建一个java类,表示代理类。
- 同时你所要代理的目标类是确定的。
- 特点:
- 实现简单
- 容易理解
- 缺点:
- 当你的项目中,目标类和代理类很多时候,有以下的缺点:
1)当目标类增加了, 代理类可能也需要成倍的增加。 代理类数量过多。
2)当你的接口中功能增加了, 或者修改了,会影响众多的实现类,厂家类,代理都需要修改。影响比较多。
- 当你的项目中,目标类和代理类很多时候,有以下的缺点:
1.3.2 动态代理
在静态代理中目标类很多时候,可以使用动态代理,避免静态代理的缺点。
1)代理类数量可以很少,
2)当你修改了接口中的方法时,不会影响代理类。
动态代理: 在程序执行过程中,使用jdk的反射机制,创建代理类对象, 并动态的指定要代理目标类。
换句话说: 动态代理是一种创建java对象的能力,让你不用创建TaoBao类,就能创建代理类对象。
参考:
(48条消息) JDK动态代理(介绍理解,如何实现)_TxCode的博客-CSDN博客_jdk动态代理
JDK动态代理
- Interface:对于 JDK 动态代理,目标类需要实现一个 Interface。
- InvocationHandler:InvocationHandler 是一个接口,可以通过实现这个接口,定义横切逻辑,再通过反射机制(invoke)调用目标类的代码,在次过程,可能包装逻辑,对目标方法进行前置后置处理。
- Proxy:Proxy 利用 InvocationHandler 动态创建一个符合目标类实现的接口的实例,生成目标类的代理对象。
使用动态代理步骤:
- 创建接口,定义目标类要完成的功能
- 创建目标实现类
- 创建 InvocationHandler 接口的实现类,在invoke方法中完成代理类的功能
- 调用目标方法
- 增强功能
- 使用Proxy类的静态方法,创建代理对象,并把放回置转为接口类型
自己写的示例
//创建接口Factory,表示一个工厂
public interface Factory {
/**
* 厂家进行销售
* @param name 需要传入的参数
*/
void sell(String name);
void refund();
}
//创建目标实现类
public class FactoryImpl implements Factory {
@Override
public void sell(String name) {
System.out.println("厂家生成货物: " + name);
}
@Override
public void refund() {
System.out.println("商家退货");
}
}
//创建 InvocationHandler 接口的实现类,在invoke方法中完成代理类的功能,相当于商家代理销售和退货
public class MyInvocationHandler implements InvocationHandler {
private Object target;//传入需要代理的类
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//根据方法名处理不同的逻辑
if(method.getName().equals("sell")){
System.out.println("------------商家代理销售------------- ");
//调用被代理类的某个方法
//传入 代理类 , 对应参数
method.invoke(target,args);
System.out.println("--------------商家代理销售完成---------------");
} else if(method.getName().equals("refund")){
System.out.println("------------商家代理退货------------- ");
//调用被代理类的某个方法
//传入 代理类 , 对应参数
method.invoke(target,args);
System.out.println("--------------商家代理退货完成---------------");
}
return null;
}
/**
* 提供Proxy静态方法,创建代理对象。
* @return
*/
public Object getProxy() {
return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
}
//主方法,使用示例
public class App {
public static void main(String[] args) {
MyInvocationHandler myInvocationHandler = new MyInvocationHandler(new FactoryImpl());
Factory proxy = (Factory) myInvocationHandler.getProxy();
proxy.refund();
}
}
CGLib动态代理
优点
- 目标类无需实现某个接口
- 执行效率较高
缺点
- Cglib原理是针对目标类生成一个子类,覆盖其中的所有方法,所以目标类和方法不能声明为final类型。
示例
//目标类
public class Dog {
public void run(String name){
System.out.println("狗" + name + "--------run");
}
public void eat(){
System.out.println("狗-------------eat");
}
}
//自定义拦截器
public class MyInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("对目标类的增强!!!");
methodProxy.invokeSuper(o,objects);
return null;
}
}
//主方法
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
//设置目标类的字节码文件
enhancer.setSuperclass(Dog.class);
//设置回调函数
enhancer.setCallback(new MyInterceptor());
//这里创建正式代理类
Dog dog = (Dog) enhancer.create();
//调用代理类的eat方法
dog.eat();
}