java设计模式(代理模式)
核心作用:
通过代理,控制对对象的访问;可以详细的控制访问某个对象的方法,在调用这个方法后做前置后置处理。是AOP(面向切面编程)的核心实现机制。可以理解为委托类委托代理类完成一个怎么怎么样的操作,代理类与委托类有相同的接口,代理类可以实现委托类同样的操作,并完成自己的操作。
核心角色:
1.抽象对象:
定义真实角色和代理角色的公共对外方法。
2.真实角色
实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用
关注真正的业务逻辑
3.代理角色
实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的方法
将统一的流程控制放到代理角色中处理
应用场景:
1.安全代理:屏蔽对真实角色的直接访问。
2.远程代理:通过代理类处理远程方法调用。
3.延迟加载:先加载轻量级的代理对象,真正需要时再加载真实对象。
比如我们要执行一个添加的操作:
//真实类和代理类共同使用的接口
interface UserDao{
void add();
}
//真实角色,需要执行一个添加操作
class UserDaoImpl implements UserDao{
@Override
public void add() {
System.out.println(" 真正类添加一个 ");
}
}
- 静态代理:
自己写代理类完成代理动作,虽然做到不修改目标对象的功能前提下,对目标功能扩展,但是每个代理类要和真实类实现同样的接口,不易维护。
class UserDaoProxy implements UserDao{
//目标对象
private UserDao userDao;
public UserDaoProxy(UserDao userDao){
this.userDao=userDao;
}
@Override
public void add() {
System.out.println(" 开始添加----> ");
userDao.add();
System.out.println(" 添加结束----> ");
}
}
//客户端调用
UserDao userDao=new UserDaoProxy(new UserDaoImpl());
userDao.add();
- 动态代理(jdk自带实现方法):
需要实现Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
方法
loader:指定当前目标对象使用类加载器
interfaces:目标对象实现的接口的类型
h:事件处理,执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的方法作为参数传入。
//代理工厂
class ProxyFactory {
//目标对象
private Object target;
public ProxyFactory(Object target){
this.target=target;
}
public Object getProxyInstance(){
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(" 开始添加----> ");
//执行委托类的操作
Object obj=method.invoke(target, args);
System.out.println(" 添加结束----> ");
return obj;
}
});
}
}
//客户端调用
UserDao userDao=(UserDao) new ProxyFactory(new UserDaoImpl()).getProxyInstance();
userDao.add();
- 动态代理(Spring使用的Cglib方式):
就是让代理类继承委托类,通过MethodInterceptor回调执行方法实现操作。
class ProxyFactory {
//目标对象
private Object target;
public ProxyFactory(Object target){
this.target=target;
}
public Object getProxyInstance(){
//工具类
Enhancer en=new Enhancer();
//设置父类
en.setSuperclass(target.getClass());
//设置回调函数
en.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object arg0, Method method, Object[] arg2, MethodProxy arg3) throws Throwable {
System.out.println(" 开始添加----> ");
//执行委托类的操作
Object obj=method.invoke(target, arg2);
System.out.println(" 添加结束----> ");
return obj;
}
});
//创建子类(代理对象)
return en.create();
}
}
- 动态代理(Javaassist字节码操作库实现)详见(javaAssist入门):
就是去操作字节码文件,在方法的前后添加代码实现额外的功能,再反射调用新生成的方法。
public class ProxyTest {
public static void main(String[] args) throws Exception{
ClassPool pool=ClassPool.getDefault();
//读取类
CtClass userDaoImpl=pool.get("com.test.UserDaoImpl");;
CtMethod cm=userDaoImpl.getDeclaredMethod("add",null);
//在方法前加入代码
cm.insertBefore("System.out.println( \" 开始添加---->!\");");
cm.insertAfter("System.out.println( \" 添加结束---->\");");
//通过反射去调用新生成的方法
Class clazz= userDaoImpl.toClass();
//调用无参构造器,创建对象
Object obj=clazz.newInstance();
Method method=clazz.getDeclaredMethod("add");
method.invoke(obj);
}
}