动态代理
代理是一种模式,提供了对目标对象的间接访问方式,即通过代理对象访问目标对象,如此便于在目标实现的基础上增加额外的功能操作,以满足自身的业务需求
即,就是给调用者不直接找到目标对象,而是通过找到中间商,中间商再给调用者找目标对象
JDK提供了java.lang.relect.InvocationHandler接口和java.lang.reflect.Proxy类这两个类为了实现动态代理
动态代理图解
@Test
public void test2() throws IllegalAccessException, InstantiationException {
//通过接口得到代理类Class对象
Class<?> proxyClass = Proxy.getProxyClass(BussinessInterface.class.getClassLoader(), BussinessInterface.class);
//通过反射创建代理类对象
Object proxy = proxyClass.newInstance();
}
但是在运行这段代码的时候,会抛出异常
这是因为newInstance()方法底层是调用的无参构造,但是Proxy类的无参构造是私有的
我们无法使用私有化的无参构造,只能使用下面的有参构造
@Test
public void test2() throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
//通过接口得到代理类Class对象
Class<?> proxyClass = Proxy.getProxyClass(BussinessInterface.class.getClassLoader(), BussinessInterface.class);
//通过反射创建代理类对象
Constructor<?> constructor = proxyClass.getDeclaredConstructor(InvocationHandler.class);
BussinessInterface proxy = (BussinessInterface) constructor.newInstance(new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;
}
});
//调用方法
System.out.println(proxy.execute());
}
得到的结果是null
是因为每次调用代理对象的方法都会调用invoke(),且invoke()的返回值就是代理方法的返回值
动态代理的大致设计思路
所以应该设法在invoke()方法得到目标对象,并调用目标对象的同名方法
private static Object getProxy(final Object target) throws Exception {
//参数1:随便找个类加载器给它, 参数2:目标对象实现的接口,让代理对象实现相同接口
Class proxyClazz = Proxy.getProxyClass(target.getClass().getClassLoader(), target.getClass().getInterfaces());
Constructor constructor = proxyClazz.getConstructor(InvocationHandler.class);
Object proxy = constructor.newInstance(new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(method.getName() + "方法开始执行...");
Object result = method.invoke(target, args);
System.out.println(result);
System.out.println(method.getName() + "方法执行结束...");
return result;
}
});
return proxy;
}
@Test
public void test2() throws Exception {
BussinessInterface proxy = (BussinessInterface)getProxy(new Bussiness());
//调用方法
proxy.execute();
}
Java实现动态代理的方式
1、JDK动态代理:java.lang.reflect 包中的 Proxy 类和 InvocationHandler 接口提供了生成动态代理类的能力。
2、Cglib动态代理:Cglib (Code Generation Library )是一个第三方代码生成类库,运行时在内存中动态生成一个子类对象从而实现对目标对象功能的扩展。
JDK原生动态代理是Java原生支持的,不需要外部依赖,但是它只能基于接口进行代理(需要动态代理的对象必须实现与某个接口)
CGLIB通过继承的方式进行代理,要导入cglib第三方库,使用的类是Enhancer的create静态方法创建,要求被代理类不能是最终类,即不能用final修饰,如String类。
使用cglib实现动态代理:
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
@Test
public void test3(){
// 创建一个被代理对象,这里要求必须是final
final Bussiness target = new Bussiness();
Bussiness proxy =(Bussiness) Enhancer.create(target.getClass(), new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
Object returnValue = null;
System.out.println(method.getName() + "方法开始执行...");
returnValue = method.invoke(target, objects);
System.out.println(method.getName() + "方法执行结束...");
return returnValue;
}
});
proxy.execute();
}