什么是代理
代理模式是一种设计模式,提供了对目标对象额外的访问方式,即通过代理对象访问目标对象,这样可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。
// 接口功能
interface UserManager{
void addUser(String id,String name);
void delUser(String id);
String findUser(String id);
void modifyUser(String id,String name);
}
静态代理
废话不多说,先上代码:
UserManagerImpl实现接口的方法,并添加子类自己的功能
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 String findUser(String userId) {
System.out.println("UserManagerImpl.findUser");
return "张三";
}
@Override
public void modifyUser(String userId, String userName) {
System.out.println("UserManagerImpl.modifyUser");
}
}
创建一个静态代理类,跟子类UserManagerImpl实现同一个接口类UserManager,然后在代理类的构造方法中传入接口类UserManager,这样就可以在子类调用前后添加你想要添加的功能,比如打印日志或者其他操作。
public class UserManagerImplProxy implements UserManager {
// 目标对象
private UserManager userManager;
// 通过构造方法传入目标对象
public UserManagerImplProxy(UserManager userManager) {
this.userManager = userManager;
}
@Override
public void addUser(String userId, String userName) {
//添加打印日志的功能
//开始添加用户
System.out.println("start-->addUser()");
// 子类实现调用
userManager.addUser(userId, userName);
//添加用户成功
System.out.println("success-->addUser()");
}
@Override
public void delUser(String userId) {
//开始添加用户
System.out.println("start-->addUser()");
userManager.delUser(userId);
}
@Override
public String findUser(String userId) {
//开始添加用户
System.out.println("start-->addUser()");
userManager.findUser(userId);
return "张三";
}
@Override
public void modifyUser(String userId, String userName) {
userManager.modifyUser(userId,userName);
}
}
客户端:
UserManager userManager = new UserManagerImplProxy(new UserManagerImpl());
userManager.addUser("1111", "张三");
打印结果为:
start-->addUser()
UserManagerImpl.addUser
success-->addUser()
代码分析:
看客户端代码可以知道我们以为使用了静态代理类UserManagerImplProxy,因此给子类UserManagerImpl的addUser()方法添加的日志打印功能,通过打印结果可以看出多了start-->addUser()和success-->addUser()两段文案。
那么如果我们要给子类UserManagerImpl的delUser()等其他方法添加新的打印日志时,是要去修改静态代理中对应的方法内容,这种代码不利于后期扩展和维护,下面要讲到动态代理,可以解决上面遇到这种问题。
动态代理
客户端代码:
UserManager targetObject = new UserManagerImpl();
//第一个参数指定产生代理对象的类加载器,需要将其指定为和目标对象同一个类加载器
//第二个参数要实现和目标对象一样的接口,所以只需要拿到目标对象的实现接口
//第三个参数表明这些被拦截的方法在被拦截时需要执行哪个InvocationHandler的invoke方法
//根据传入的目标返回一个代理对象
UserManager userManager =
(UserManager) Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object ret = null;
System.out.println("satrt-->>");
//调用目标方法 被代理类的方法
ret = method.invoke(targetObject, args);
/*原对象方法调用后处理日志信息*/
System.out.println("success-->>");
return ret;
}
});
userManager.addUser("", "");
userManager.findUser("");
打印结果:
satrt-->>
UserManagerImpl.addUser
success-->>
satrt-->>
UserManagerImpl.findUser
success-->>
代码分析:
通过动态代理类:Proxy.newProxyInstance中实现InvocationHandler的invoke方法中添加对代理类的拦截操作,如日志写入等,返回代理类对象。
动态代理可以实现对接口UserManager中全部的方法进行统一的拦截,不需要在每一处代理方法中添加拦截内容。
动态代理是AOP的一种实现。
AOP(AspectOrientedProgramming):将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码---解耦。
动手撸一下代码,理解更容易。