先看例子,demo 是一个增删改查的数据库操作,但我想在增加的这个操作上打一个日志,用来输出,可以用静态代理完成。
//接口
interface UserManager {
/**
* 增加
*
* @param userId
* @param userName
*/
void addUser(String userId, String userName);
/**
* 删除
*
* @param userId
*/
void delUser(String userId);
/**
* 查找
*
* @param userId
* @return
*/
String findUser(String userId);
/**
* 修改
*
* @param userId
* @param userName
*/
void modifyUser(String userId, String userName);
}
//用户管理实现类
public class UserManagerImpl implements UserManager {
@Override
public void addUser(String userId, String userName) {
System.out.println("UserManagerImpl.addUser");
}
@Override
public void delUser(String userId) {
System.out.println("UserManagerImpl.delUser");
}
@Override
public void modifyUser(String userId, String userName) {
System.out.println("UserManagerImpl.modifyUser");
}
@Override
public String findUser(String userId) {
System.out.println("UserManagerImpl.findUser");
return "张三";
}
}
//代理用户管理实现类
public class UserManagerImplProxy implements UserManager {
// 目标对象
private UserManager userManager;
// 通过构造方法传入目标对象
public UserManagerImplProxy(UserManager userManager) {
this.userManager = userManager;
}
@Override
public void addUser(String userId, String userName) {
try {
//开始添加用户
System.out.println("start-->addUser()");
//执行添加的功能
userManager.addUser(userId, userName);
//添加用户成功
System.out.println("success-->addUser()");
} catch (Exception e) {
//添加用户失败
System.out.println("error-->addUser()");
}
}
@Override
public void delUser(String userId) {
userManager.delUser(userId);
}
@Override
public String findUser(String userId) {
userManager.findUser(userId);
return "张三";
}
@Override
public void modifyUser(String userId, String userName) {
userManager.modifyUser(userId, userName);
}
}
//客户端调用类
public class Client {
public static void main(String[] args) {
UserManager userManager = new UserManagerImplProxy(new UserManagerImpl());
userManager.addUser("1111", "张三");
}
执行结果:
start-->addUser()
UserManagerImpl.addUser
success-->addUser()
静态代理类优缺点
优点:
代理使客户端不需要知道实现类是什么,怎么做的,而客户端只需知道代理即可(解耦合)。
缺点:
1)代理类和委托类实现了相同的接口,代理类通过委托类实现了相同的方法。这样就出现了大量的代码重复。如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。
2)代理对象只服务于一种类型的对象,如果要服务多类型的对象。势必要为每一种对象都进行代理,静态代理在程序规模稍大时就无法胜任了。如上的代码是只为UserManager类的访问提供了代理,但是如果还要为其他类提供代理的话,就需要我们再次添加其它类的代理类。
动态代理:
代理类在程序运行前不存在、运行时由程序动态生成的代理方式称为动态代理。
例子看studio暂未贴出
1.被代理对象targetObject通过参数传递进来
2.通过反射targetObject.getClass().getClassLoader()获取ClassLoader对象
3.反射通过targetObject.getClass().getInterfaces()获取它实现的所有接口
4.然后将targetObject包装到实现了InvocationHandler接口的LogHandler对象中
5.最后通过newProxyInstance函数我们就获得了一个动态代理对象。
在java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface)、另一个则是 Proxy(Class),这两个类和接口是实现我们动态代理所必须用到的。
InvocationHandler类:
注释
InvocationHandler is the interface implemented by the invocation handler of a proxy instance.
Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, the method invocation is encoded and dispatched to the invoke method of its invocation handler.
每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
proxy:
指代我们所代理的那个真实对象
method:
指代的是我们所要调用真实对象的某个方法的Method对象
args:
指代的是调用真实对象某个方法时接受的参数
Proxy类:
动态创建一个代理对象的类
public static Object newProxyInstance(ClassLoader var0, Class<?>[] var1, InvocationHandler var2) throws IllegalArgumentException
loader: 一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
interfaces: 一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
h: 一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
打印的日志:
invok调用开始
args = 1111
args = 张三
处理日志
UserManagerImpl.addUser
public abstract void com.example.DynamicProxy.UserManager.addUser(java.lang.String,java.lang.String)
invok调用成功
可以看到method打印出来的com.example.DynamicProxy.UserManager.addUser(java.lang.String,java.lang.String) 是符合newProxyInstance中第二个参数
targetObject.getClass().getInterfaces()
动态代理生成的都是二进制class字节码:
Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
1.InvocationHandler参数对象中加入了代理的接口类的实现类
2.通过Proxy.newProxyInstance产生$Proxy0类,它继承Proxy对象,并根据第二个参数,实现了被代理类的所有接口
3.ClassLoader-代理类的类加载器,把当前的代理类加载到JVM中
动态代理生成的都是二进制class字节码
优点:
可以方便对代理类的函数做统一或特殊处理,如记录所有函数执行时间、所有函数执行前添加验证判断、对某个特殊函数进行特殊操作,而不用像静态代理方式那样需要修改每个函数。