动态代理的好处
Java动态代理的优势是实现无侵入式的代码扩展,也就是方法的增强;让你可以在不用修改源码的情况下,增强一些方法;在方法的前后你可以做你任何想做的事情(甚至不去执行这个方法就可以)。此外,也可以减少代码量,如果采用静态代理,类的方法比较多的时候,得手写大量代码。
动态代理示例:
接口类:
public interface UserService {
public abstract void add();
public abstract void update();
}
接口实现类:
public class UserServiceImpl implements UserService {
public void add() {
System.out.println("----- add -----");
}
public void update(){
System.out.println("----- update-----");
}
}
代理处理类MyInvocationHandler.java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
//注入目标对象,方便在invoke中调用目标对象的目标方法
super();
this.target = target;
}
public Object getProxy() {
return Proxy.newProxyInstance(Thread.currentThread()
.getContextClassLoader(), target.getClass().getInterfaces(),
this);
//指定代理类生成时的加载器,要实现的接口,代理类的代理方法被调用时需要调用哪个对象的invoke方法。
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//代理类的代理方法被调用时,会调用传入的h对象的invoke方法。
System.out.println("----- before -----");
Object result = method.invoke(target, args);
//调用真正的目标类的目标方法。
System.out.println("----- after -----");
return result;
}
}
测试类:
public class DynamicProxyTest {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
MyInvocationHandler invocationHandler = new MyInvocationHandler(
userService);
UserService proxy = (UserService) invocationHandler.getProxy();
proxy.add();
proxy.update();
}
}
输出:
----- before -----
----- add -----
----- after -----
----- before -----
----- update -----
----- after -----
其基本过程如下: 1.定义目标类接口和目标类 2.实现InvocationHandler接口,在构造方法中注入目标类,实现获取代理类的方法getProxy() ,该方法中调用Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), target.getClass().getInterfaces(), this); 传入的类加载器用于加载生成的代理类的字节码(ProxyGenerator.generateProxyClass()的方法是最终生成代理类的字节码.),传入的接口(可以为多个)用于规定生成的代理类需要代理的方法有哪些,传入的this对象必须是InvocationHandler的实现类对象(称为h对象),因为最终生成的代理对象的方法在被调用是全部是通过转发给对象h的invoke方法来处理的,你可以在invoke方法中通过method.invoke(target, args);来调用目标类的方法,同时在调用之前或者之后加入自己的功能代码。
//重点就是这里,代理类实现的接口方法
public final void sayHello(String paramString) {
try {
//见上面构造方法,this.h 就代表MyInvocationHandler类,所以执行的就是我们代理实现类中的invoke方法。
this.h.invoke(this, m3, new Object[] { paramString });
return;
}
catch (Error|RuntimeException localError) {
throw localError;
}
catch (Throwable localThrowable) {
throw new UndeclaredThrowableException(localThrowable);
}
}
我们可以把 InvocationHandler 看做一个中介类,中介类持有一个被代理的目标对象,在 invoke 方法中调用了目标对象的相应方法,而生成的代理类中持有中介类,因此,当我们在调用代理类的方法的时候,调用被转发到中介类h的 invoke 方法,再转为对被目标对象的调用。
生成的代理类:$Proxy0 extends Proxy implements Person,我们看到代理类继承了 Proxy 类,由于java中的单继承,所以也就决定了生成的 java 动态代理类不能再继承其它类,只能对接口进行代理,所以Java 的动态代理类无法实现直接针对 类的动态代理,只能通过接口间接实现对类的动态代理。