Java代理模式—动态代理
Java代理模式是比较常用的代理模式之一,常用于框架当中。比如spring框架中切面是实现,MyBatis中获取数据库链接,关闭数据库链接等。
个人理解:代理模式主要是会生成一个代理对象,这个代理对象是被JVM监控的。当我要去调用这个代理对象其中的某个方法时JVM会监控这个方法的调用,并执行通知通知对象的invoke()方法。
比如:我有一个吃饭的方法,我需要在吃饭前洗手。那么我在调用吃饭这个方法时JVM会将其拦截,然后先去执行洗手再去执行吃饭。
这个代理对象是由JVM生成的。代理对象生成的条件是:1)有一个接口(主要业务的接口)。 2)有这个接口的实现类。 3)有通知对象(也就是主要业务接口与次要业务接口融合的对象)。
例子:吃饭前要洗手,上厕所后要洗手
首先我们要确定,吃饭和上厕所是我们的主要业务,洗手是次要业务。
首先我们先确定一个接口,这个接口中有吃饭的方法和上厕所的方法。
定义接口BaseService
public interface BaseService {
public void eat();
public void wc();
}
确定完接口之后我们书写一个实现类Person
public class Person implements BaseService {
public void eat() { //我们一般会在这里书写主要业务
System.out.println("我在吃饭..");
}
public void wc() {
System.out.println("我在上厕所..");
}
}
接口和实现类定义完成后我们需要一个通知对象,这个通知对象的作用是将核心业务(吃饭、上厕所)与次要业务(洗手)进行合并。
要实现通知对象必须是java.lang.reflect.InvocationHandler接口的实现类。
public class Invocation implements InvocationHandler {
private BaseService obj; //具体被监控的对象
public Invocation(BaseService obj){
this.obj = obj;
}
/**
* invoke方法:在被监控行为将要执行的时候,JVM进行拦截
* 被监控行为和行为实现方会以参数的形式传递给invoke方法中
* 主要做主要业务与次要业务之间的调用关系
*
* Object:监控方法的代理对象
* Method:被监控的方法
* Object[]:就是被监控方法的参数列表
*
* 返回Object:指监控方法的之后返回值
*/
public Object invoke(Object arg0, Method method, Object[] param) throws Throwable {
String methodName = method.getName();
Object result;
if("eat".equals(methodName)){ //吃饭方法
//核心业务与次要业务进行合并
hand();
result = method.invoke(obj, param);
}else{
result = method.invoke(obj, param);
hand();
}
return result;
}
/**
* 次要业务方法实现
*/
public void hand(){
System.out.println("我在洗手...");
}
}
最后我们需要一个可以为我们产生代理对象的工厂方法:
public class ProxyFactory {
public static BaseService builder(Class cla) throws Exception{
/**
* 创建被监控实例对象
* 实现一个被监控的实例对象
*/
BaseService obj = (BaseService) cla.newInstance();
//实现通知对象
/**
* 创建一个通知对象
*/
InvocationHandler adviser = new Invocation(obj);
//进行注册,让JVM生成一个代理对象(通过被监控类和通知对象)
/**
* 向JVM申请一个负责监控obj对象指定行为的监控对象(代理对象)
*
* 参数:
* loader:被监控对象隶属的类文件在内存中的真实地址
* interface:被监控对象隶属的类文件实现接口
* h:通知对象
*/
BaseService $proxy = (BaseService)Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), adviser);
return $proxy;
}
}
全部完成后书写我们的测试类:
public class TestMain {
public static void main(String[] args) throws Exception {
BaseService obj = ProxyFactory.builder(Person.class);
obj.eat();
obj.wc();
}
}
执行结果:
这些是今天学习的一部分内容,如果您在上述文章中发现有错误的地方欢迎您指出来我会积极去改正。