提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
代理模式是学习Aop的前置知识,因为Aop的底层就是用代理模式分片的,但是说实话,代理模式我认为比较难写得清楚,所以这里就用自己的想法把代理模式写出来,但是我觉得只能写出来一个大概,所以具体是怎么实现的,建议去看视频(因为我也是看视频看懂的),这个文章只是用来自己学习的,各位大佬轻喷 T-T
一、静态代理
问题引入;
若我们需要实现一个加法功能,并且在实现这个功能之前和之后打印日志信息
这时我们代码可以这么写
public int add(int i , int j){
//这里我们可以在实现日志功能的同时,在方法前分别打印日志信息
System.out.println("两数分别为:"+i+","+j);
int sum = i + j;
System.out.println("返回结果:"+sum);
return sum;
}
这时候我们会发现一个问题,这么写太死了,也就是日志信息代码(也就是 System.out.println(“两数分别为:”+i+“,”+j)和逻辑代码( int sum = i + j;)是杂糅在一起的,他们不分开,这时候如果我们想让它们各自处理各自的事务就可以添加一个类,将业务代码和日志代码分开
然后有了下面这个类
public class StaticProxyStudent implements calcolator{
//第二步
private calculatorImp cal;
public StaticProxyStudent(calculatorImp cal) {
this.cal = cal;
}
@Override
public int add(int i, int j) {
System.out.println("两数分别为:"+i+","+j);
int result = cal.add(i,j);
System.out.println("返回结果:"+result);
return result;
}
}
二、动态代理
问题引入
看了上面的代码,我们会发现一个问题,他的代码是写死的,也就是说,我们创建了一个类的静态代理,那么这个静态代理只能给这一个类实现解耦的功能,例如StaticProxyStudent只能给calculatorImp实现功能,显然这种方式不灵活,将来我们需要其他的类也添加日志功能就必须要创建更多的类,就显得很麻烦而且重复代码很多,又没有统一管理, 这时候动态管理就实现了;动态管理只需要创建一个类就可以实现其他的类的额外操作的管理功能,例如日志操作
----也就是说动态代理可以将任何类放进来进行日志的一个管理,他并不像静态代理一样只针对单一的一个类进行管理
下面是动态代理的代码和注释
解释在代码的注释中
注意的是;jdbc的动态代理是必须实现和被代理类同样的接口的
public class poxyFactory {
//既然要代理一个类,那么显然我们需要有一个目标对象,但是我们并不知道这个目标对象是哪一个类,所以用object接收
// (后期永转型就可以转型为自己对应的类)
private Object target;
//创建有参构造进行赋值
public poxyFactory(Object target) {
this.target = target;
}
//在这里就是获取目标对象的代理类了
public Object getPoxy(){
/*
* ClassLoader loader,指定加载动态生成的代理类的类加载器
* (获取类加载器是因为我们这个方法是需要生成一个代理类的,而我们需要指定这个类的加载器是需要什么加载器实现的)
*/
ClassLoader classLoader = this.getClass().getClassLoader();
//Class<?>[] interfaces,获取目标对象实现的所有接口的class对象数组
//在静态代理类中我们知道,代理类必须和目标的类实现同一个接口,这个参数就是存放目标类的接口的)
Class<?>[] interfaces = target.getClass().getInterfaces();
// InvocationHandler h;设置抽象方法如何重写
//这里就是如何重写接口中的方法的(匿名内部类)
InvocationHandler h = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//proxy表示需要代理的对象;method表示需要执行的方法,args表示执行方法的参数列表
Object result = method.invoke(target,args);
/*
* 这里需要稍微注意一下,为什么method.invoke会自动调用calculatorImp中的方法呢,
* 事实上在我们执行这段代码的时候,在内存中会自动的加载一个名字叫做$proxy2的类,该类将
* 我们需要实现的方法封装到了method中,因为这个实在内存中实现的,所以看不见
* 所以我们调用method.invoke其实就是调用了自己的方法
* */
return result;
}
};
注意proxy是反射包下的Proxy
return Proxy.newProxyInstance(classLoader,interfaces,h);//获取代理类实例
}
}
事实上,上面的代码是一套模板,只需要照抄也可以实现对应的功能,但是它可以帮助我们理解aop的实现原理,下面是照抄之后如何实现功能
测试类
@Test
public void testpoxy2(){
poxyFactory poxyFactory = new poxyFactory(new calculatorImp());
calcolator poxy = (calcolator)poxyFactory.getPoxy();
poxy.add(1,2);
}
这里补充一下怎么添加日志功能,这时候只需要加入try-catch就可以实现了
InvocationHandler h = new InvocationHandler() {
try {
sout("日志")
Object result = method.invoke(target,args);
return result;
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} finally {
sout("日志")
}
}
}
};