在Java开发中如果一个类中的方法在基本功能之外需要进行功能扩充或者功能增强,如:事务控制、权限判断、日志记录等等操作,此时可以使用动态代理机制。
代理协助本体进行功能的增强
动态代理是在不需要修改源代码的基础上对原有类的功能进行增强
代码示例
1.创建接口,定义接口的规范;
/**
* 演员接口
*/
public interface Actor {
//音乐表演
void musicAct(int money);
//舞蹈表演
void danceAct(int money);
//娱乐表演
void yuLeAct(int money);
}
2.定义实现接口的子类,实现接口定义的方法,此方法只需要把核心功能实现即可,其他增强的操作可以在代理类中实现。
public class ActorImpl implements Actor {
@Override
public void musicAct(int money) {
System.out.println("音乐表演...花了"+money);
}
@Override
public void danceAct(int money) {
System.out.println("舞蹈表演...花了"+money);
}
@Override
public void yuLeAct(int money) {
System.out.println("娱乐表演...花了"+money);
}
}
3. 定义代理类,在代理类中对被代理对象进行方法增强。
1、Proxy.newProxyInstance的三个参数
Actor actorProxy = (Actor) Proxy.newProxyInstance(ActorImpl.class.getClassLoader(), ActorImpl.class.getInterfaces(), new InvocationHandler() {
}
2、invoke方法的三个参数
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {}
/**
* 动态代理机制
* 代理类可以给某个类的某个方法进行代理,负责完成被代理对象的一些功能实现。Java的Proxy用来创建代理对象
*/
public class Clint {
public static void main(String[] args) {
//1.定义被代理类
ActorImpl actor = new ActorImpl();
/**
* 2.创建代理对象
* ClassLoader Loader:被代理的类的加载器(我要代理谁)
* Class>[] interfaces:被代理对象的接口(我要代理的对象继承了那个接口,就知道代理对象可以完成哪些功能)
* InvocationHandler h:执行处理(代理之后我要做什么)
*/
Actor actorProxy = (Actor) Proxy.newProxyInstance(ActorImpl.class.getClassLoader(), ActorImpl.class.getInterfaces(), new InvocationHandler() {
/**
* Object proxy:被代理对象的引用,系统会自动创建被代理对象的一个映射
* Method method:被代理对象的方法
* Object[] args:被代理对象的方法的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//获取方法三要素:方法名、参数、返回值
String methodName = method.getName();//代理对象执行的方法
//获取代理对象执行的时候传入的参数
int money = (int) args[0];
//定义代理对象执行方法的返回值
Object result = null;
//要对哪个方法进行增强
if(methodName.equals("musicAct")){
//增强操作
System.out.println("核酸检测....");
System.out.println("健康码检测....");
System.out.println("行程码检测....");
//执行被代理对象的方法
result = method.invoke(actor,money);
//增强操作
System.out.println("收取代理费用"+money*0.05);
return result;
}
return result;
}
});
//3.有代理对象执行方法的时候不再是被代理对象执行方法,而是由我们的代理类对象执行方法
actorProxy.musicAct(500);
}
}
日志打印
基于子类的CGLib动态代理,可以使用Enhancer类完成直接对某个类进行动态代理;
CGLIB动态代理
CGLIB(Code Generation Library)是一个强大的高性能的代码生成包。它被许多AOP的框架广泛使用,例如,Spring AOP和dynaop为它提供方法的interception(拦截)。流行的ORM框架Hibernate也使用CGLIB来实现延迟加载。
CGLIB 原理:动态生成一个要代理类的子类,子类重写要代理的类的所有不是 final 的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。
CGLIB 底层:采用ASM字节码生成框架,使用字节码技术生成代理类,比使用 Java 反射效率要高。
代码示例
1.创建被代理的类,并定义功能方法,完成核心功能即可。不需要实现接口;
public class Actor {
public void musicAct(int money) {
System.out.println("音乐表演...花了"+money);
}
public void danceAct(int money) {
System.out.println("舞蹈表演...花了"+money);
}
public void yuLeAct(int money) {
System.out.println("娱乐表演...花了"+money);
}
}
2.定义代理类,使用Enhancer创建代理对象,对被代理对象进行方法增强。
1、Enhancer.create的2个参数
Actor proxyActor = (Actor) Enhancer.create(Actor.class, new MethodInterceptor() {}
Class type
被代理类的class文件Callback callback
一个Callback接口,我们通常使用MethodInterceptor
接口,继承了Callback接口2、intercept方法的参数
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {}
Method method
当前方法Object[] objects
方法用到的参数数组