动态代理
特点:
字节码随用随创建,随用随加载。
作用:
不修改源码的基础上对方法增强。
分类
基于接口的动态代理
提供者:JDK 官方的 Proxy 类。
要求:被代理类最少实现一个接口。
利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
基于子类的动态代理
提供者:第三方的 CGLib,如果报 asmxxxx 异常,需要导入 asm.jar。
要求:被代理类不能用 final 修饰的类(最终类)。
利用ASM(开源的Java字节码编辑库,操作字节码)开源包,将代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。
基于接口的动态代理
模拟人的行为
Person
public interface Person {
//日常行为
void dailyBehavior();
}
Student
public class Student implements Person {
private String msg = "学生党";
public void dailyBehavior() {
System.out.println("睡觉");
System.out.println("吃饭");
}
}
PersonProxy
public class PersonProxy implements InvocationHandler {
private Person person;
public PersonProxy(Person person){
this.person = person;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
method.invoke(person,args);
if(person instanceof Student){
System.out.println("去学校上课");
}
if(person instanceof Student){
System.out.println("放学回家");
}
return null;
}
}
test
public class test {
public static void main(String[] args) {
Student student = new Student();
PersonProxy personProxy = new PersonProxy(student);
Person o = (Person)Proxy.newProxyInstance(test.class.getClassLoader(),student.getClass().getInterfaces(), personProxy);
o.dailyBehavior();
}
}
结果
睡觉
吃饭
去学校上课
放学回家
基于子类的动态代理
父类
public class SayHello {
public void say(){
System.out.println("hello everyone");
}
}
代理类
public class CglibProxy implements MethodInterceptor{
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class clazz){
//设置需要创建子类的类
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
//通过字节码技术动态创建子类实例
return enhancer.create();
}
//实现MethodInterceptor接口方法
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println("前置代理");
//通过代理类调用父类中的方法
Object result = proxy.invokeSuper(obj, args);
System.out.println("后置代理");
return result;
}
}
/*该类实现了创建子类的方法与代理的方法。
getProxy(SuperClass.class)方法通过入参即父类的字节码通过扩展父类的class来创建代理对象。
intercept()方法拦截所有目标类方法的调用,
obj表示目标类的实例,
method为目标类方法的反射对象,
args为方法的动态入参,
proxy为代理类实例。
proxy.invokeSuper(obj, args)通过代理类调用父类中的方法
*/
test
public class DoCGLib {
public static void main(String[] args) {
CglibProxy proxy = new CglibProxy();
//通过生成子类的方式创建代理类
SayHello proxyImp = (SayHello)proxy.getProxy(SayHello.class);
proxyImp.say();
}
}
结果
前置代理
hello everyone
后置代理
内部类形式
public static void main(String[] args) {
SayHello sayHello = (SayHello)Enhancer.create(SayHello.class,
new MethodInterceptor() {
@Override
public Object intercept(Object proxy, Method method, Object[] args,
MethodProxy methodProxy) throws Throwable {
System.out.println("前置代理");
//通过代理类调用父类中的方法
Object result = proxy.invokeSuper(obj, args);
System.out.println("后置代理");
return result;
}
});
}