代理设计模式
- 代理模式的基本结构
代理设计模式的核心思想就是:一个接口有若干个子类,其中有一个是真实主题类,负责真实的操作,要想完成这一功能必须有代理类负责,以学生上课和看门大爷为例:
观察程序的执行:
package com.csii.wanghaoxin.demob;
interface Subject{
public void study();
}
class RealSubject implements Subject{
@Override
public void study() {
System.out.println("好好学习");
}
}
class ProxySubject implements Subject{
private Subject subject;
public ProxySubject(Subject subject){
this.subject = subject;
}
public void open(){
System.out.println("开教室的门,并打扫");
}
public void close(){
System.out.println("赶学生离开,打扫卫生,关门");
}
@Override
public void study() {
this.open();
this.subject.study();
this.close();
}
}
class Factory{
public static Subject getInstance(){
return new ProxySubject(new RealSubject());
}
}
public class TestProxyDemo {
public static void main(String[] args) {
Subject sub = Factory.getInstance();
sub.study();
}
}
这个就是最原始的代理,但是需要知道的是可以有多层代理。
- 代理模式应用
现在就以核心的MVC设计模式为主,
传统的模式会建立多个ServiceImpl以及多个DaoImpl,即业务逻辑层和数据库处理层,但是有时候多个数据层的操作可能必须属于同一个业务逻辑,即事务控制,需要事务控制:
于是进一步思考,一个项目中可能会有无数个业务层,那么就意味着所有牵扯到数据更新的操作都会面临着同样的几个步骤:
1.打开数据库
2.取消事务自动提交
3.进行数据层调用
4.手工处理事务
5.关闭数据库
将辅助业务功能和核心业务功能进行区分,将基础操作和核心业务分离
如果一个业务层就要有一个代理类和真实主题类,代码会很多,—-这是静态代理。缺点”一个代理类只能为一个真是类服务
动态代理:能代理所有的操作
- 动态代理
如果按照之前的思路,假设说有500个业务层子类,那么就需要准备出500个代理类,但是最重要的是500个代理类有何区别
如果要想使用动态代理类,就必须动态生成代理对象。它依靠真实主题类的对象接口定义生成。如果要想动态创建代理对象,则需要使用Proxy类
Proxy类核心方法
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
这个类定义有一个重要方法,根据指定真实主题类的接口动态创建一个代理类的对象操作。
参数的作用如下:
ClassLoader:取得真实主题的类加载器
Class<?>[] interfaces:真实主题类实现的所有接口
InvocationHandler h:代理设计的动态生成类,真正的代理结构定义的操作。
如果要定义动态代理类,那么必须要实现InvocationHandler接口。在整个接口里面定义有一个invoke的方法。
Object invoke(Object proxy,
Method method,
Object[] args)
throws Throwable
参数:Object Proxy:被代理的对象(代理对象)
Method method:要执行的操作方法:
Object[] args:方法所需要的参数
invoke方法完善后:
以后包括在面试之中,如果出现了代理设计模式的编写, 写出此程序,可以得到百分之八十的认同
切面设计+动态代理 更方便
- *CGLIB实现动态代理设计模式
不管是代理设计模式还是动态代理设计模式都会存在有一个致命问题,必须使用接口处理,包括动态代理也存在同样的问题。
getInterfaces()
动态代理是依据对象所在类的接口来创建一个动态代理类对象进行操作的。但是哪里有压迫,哪里就有反抗,于是又一类人提出了一个观点:不用接口还要使用动态代理类。所以就产生了第三方的组件包:CGLIB组件,这个组件可以避免接口的使用,父类来进行代理操作。
可以通过sourceforce.net(sf.net)上下载CGLIB的开发包
CGLIB还是要使用动态代理设计的结构完成,如果不使用接口,则必须依靠另外一个抽象类来完成:
同时对于Proxy也需要更换为Enhancer。
范例:实现动态代理设计模式
虽然CGLIB的动态代理设计不依靠接口,但是必须要找到一个共同点,那么就依靠类。
package com.wanghaoxin.demo;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
class Messge{
public void print(){
System.out.println("Hello");
}
}
class ProxyImpl implements MethodInterceptor{
private Object target;//被代理的真实主题
public ProxyImpl(Object target){//保存了真实主题类的对象
this.target = target;
}
@Override
public Object intercept(Object proxy, Method method, Object[] arg2, MethodProxy mproxy)
throws Throwable {
System.out.println("操作准备");
Object rev = method.invoke(this.target);
System.out.println("操作结束");
return rev;
}
}
public class TestProxyDemoC {
public static void main(String[] args) {
Messge msg = new Messge();
Enhancer eh = new Enhancer();//帮助用户实现代理的工具类
eh.setSuperclass(Messge.class);//设置一个父类,这是一个模拟的过程
eh.setCallback(new ProxyImpl(msg));//操作的回调过程
Messge mg = (Messge)eh.create();
mg.print();
}
}
- 总结
在实际开发中,代理设计模式最大的优点在于:完成辅助功能,本质上就是处理事务。
代理设计模式必须依靠接口存在,动态代理设计模式也同样如此。
CGLIB开发包不需要接口实现动态代理