静态代理
想学,动态代理,须先知道什么是静态代理:【设计模式】静态代理
在编译时就已经将接口、被代理类、代理类等确定下来。在程序运行之前,代理类的.class文件就已经生成。最后带着这些确定的类运行程序。代理类在程序之前创建的代理方式被成为静态代理。
动态代理引出
而动态代理是指代理类在程序运行时创建的代理方式被成为动态代理。然而动态代理,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的。相比于静态代理, 动态代理的优势在于,当我们存在多个代理类时,它可以很方便的对代理类进行统一的处理,而不用修改每个代理类中的方法。
我们直接上代码:仍然按照之前学静态代理举得的例子:
如下是UserManager和 UserManagerImpl的代码:UserManagerImpl实现了UserManager。
以下只是作为演示。
public interface UserManager {
void addUser();
void delUser();
void findUser();
void modifyUser();
}
public class UserManagerImpl implements UserManager {
@Override
public void addUser() {
System.out.println("UserManagerImpl.addUser");
}
@Override
public void delUser() {
System.out.println("UserManagerImpl.delUser");
}
@Override
public void findUser() {
System.out.println("UserManagerImpl.findUser");
}
@Override
public void modifyUser() {
System.out.println("UserManagerImpl.modifyUser");
}
}
=============================================================
1.定义一个LogHandler类(用来打印日志信息的Handler类)实现InvocationHandler类
2.在LogHandler类里重新包装Proxy.newProxyInstance(用来返回代理对象)
3.重写invoke方法,将核心业务(如打印日志)写进去。
public class LogHandler implements InvocationHandler {
private Object target;//target千变万化,在这里其实就是实现类UserManagerImpl的对象(new UserManagerImpl)
public Object newProxyInstance(Object target){
this.target = target;//这个必须写,把方法作用域的target传给本类的target,否则invoke的target为null
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),this);//返回代理对象
}
@Override
/*proxy表示代理,method表示原对象被调用的方法,args表示方法的参数*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result;
try {
System.out.println("start-->");
result = method.invoke(target, args);//调用了target的具体方法
System.out.println("success-->");
}catch (Exception e){
e.printStackTrace();
System.out.println("error-->>");
throw e;
}
return result;
}
}
对于LogHandler类:
newProxyInstance:返回代理的方法,这个过程为动态生成。没有一个具体的代理类能被看见。
invoke:调用实现类的对象的目标方法(替代目标方法)。
public class Client {
public static void main(String[] args) {
LogHandler logHandler = new LogHandler();
UserManager proxyInstance = (UserManager) logHandler.newProxyInstance(new UserManagerImpl());//把实现类动态的托管给代理对象
proxyInstance.addUser();//代理调用
proxyInstance.delUser();
}
}
通过debug发现,proxyInstance.addUser();这一行,实际上是调用LogHandler.invoke方法,method参数其实就是原来实现类对象中的addUser方法,method.invoke(target, args)才是调用了addUser方法,所以proxyInstance.addUser();走完是这样的:(proxyInstance.delUser();同理)
画个图总结一下吧:
代理对象proxy不能直观的显示出,由newProxyInstance创建,创建出来后,可以直观上调用目标实现类的方法,但其实质上是调用invoke方法,在invoke方法里才是调用目标实现类的方法,并且在此方法前后做业务拓展。
其次,动态代理模式下的代理对象proxy可以管理多个同一接口下的实现类。
动态代理优点:
- 一个代理类代理一个接口,一个接口对应的一类业务(例如本demo中的userManager用户管理)
- 一个代理类可以管理多个同一接口下的实现类。
- 接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理(InvocationHandler.invoke)。这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。
- 动态代理的应用使我们的类职责更加单一,复用性更强。