代理模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象。
这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。
这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,可以通过代理的方式来扩展该方法。
代理模式的关键点是:代理对象与目标对象,代理对象是对目标对象的扩展,并会调用目标对象
静态代理 Demo
/**
* 接口
*/
public interface Count {
void queryCount();
void updateCount();
}
/**
* 接口实现,目标对象
*/
public class CountImpl implements Count {
@Override
public void queryCount() {
System.out.println("查看账户。。。");
}
@Override
public void updateCount() {
System.out.println("修改账户。。。");
}
}
/**
* 代理对象,静态代理
*/
public class CountProxy implements Count {
// 接受保存目标对象
private Count count;
public CountProxy(Count count) {
this.count = count;
}
@Override
public void queryCount() {
System.out.println("查询账户预处理。。。");
count.queryCount();
System.out.println("查询账户预之后。。。");
}
@Override
public void updateCount() {
System.out.println("修改账户预处理。。。");
count.updateCount();
System.out.println("修改账户预之后。。。");
}
}
/**
* 测试类
*/
public class ProxyTest {
public static void main(String[] args) {
// 目标对象
Count count = new CountImpl();
// 代理对象,把目标对象传给代理对象,建立代理关系
CountProxy proxy = new CountProxy(count);
// 执行的是代理的方法
proxy.queryCount();
proxy.updateCount();
}
}
静态代理:可以做到在不修改目标对象的功能前提下,对目标功能扩展。
缺点
因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类,类太多,同时,一旦接口增加方法,目标对象与代理对象都要维护。
如何解决静态代理中的缺点呢?答案是可以使用动态代理方式
两种常用的动态代理
- 基于接口的动态代理
- 提供者 JDK
- 使用JDK官方的Proxy类创建代理对象
- 注意:代理的目标对象必须实现接口
- 基于类的动态代理
- 提供者 第三方CGLib
- 使用CGLib的Enhancer类创建代理对象
动态代理(JDK实现)Demo
/**
* 接口
*/
public interface Count {
void queryCount();
void updateCount();
}
/**
* 接口实现,目标对象
*/
public class CountImpl implements Count {
@Override
public void queryCount() {
System.out.println("查看账户。。。");
}
@Override
public void updateCount() {
System.out.println("修改账户。。。");
}
}
/**
* 动态代理
*/
public class DynamicProxy implements InvocationHandler {
// 维护一个目标对象
private Object object;
public DynamicProxy(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("操作前预处理");
Object result = method.invoke(object, args);
System.out.println("操作后后处理");
return result;
}
}
/**
* 测试类
*/
public class DynamicProxyTest {
public static void main(String[] args) {
// 目标对象
Count count = new CountImpl();
// 生产代理对象
Count proxyInstance = (Count) Proxy.newProxyInstance(Count.class.getClassLoader(), new Class[]{Count.class}, new DynamicProxy(count));
proxyInstance.queryCount();
proxyInstance.updateCount();
}
}
动态代理(CGLib实现)Demo
/**
* 目标对象,没有实现任何接口
*/
public class Count {
public void queryCount() {
System.out.println("查看账户。。。");
}
public void updateCount() {
System.out.println("修改账户。。。");
}
}
/**
* Cglib子类代理工厂
*/
public class CglibProxy implements MethodInterceptor {
private Object object;
public Object getInstance(Object object) {
this.object = object;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.object.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("操作前预处理");
methodProxy.invokeSuper(o, objects);
System.out.println("操作后预处理");
return null;
}
}
/**
* 测试类
*/
public class CglibProxyTest {
public static void main(String[] args) {
Count count = new Count();
CglibProxy cglibProxy = new CglibProxy();
Count instance = (Count) cglibProxy.getInstance(count);
instance.queryCount();
instance.updateCount();
}
}
在Spring的AOP编程中:
如果加入容器的目标对象有实现接口,用JDK代理
如果目标对象没有实现接口,用CGLib代理
网友评论