JDK动态代理只能代理接口,所以我们需要先准备一个接口,以及一个接口的实现类
// 需要代理的接口
public interface InvokeInterface {
void test1(String test,int[] ints);
String test3(String test);
}
//代理接口的实现类
public class InvokeBean implements InvokeInterface{
public void test1(String test,int[] ints){
System.out.println("代理实现方法1 :"+test + JSON.toJSON(ints));
}
public String test3(String test){
System.out.println("代理实现方法1 :"+test);
return test;
}
}
有了代理的目标对象了,我们自然还需要一个处理方法,毕竟我们需要实现额外的逻辑呀,不然代理干嘛?对吧,这个处理方法可不能乱写,需要实现InvocationHandler接口,里面有个invoke方法,就是给我们自己写逻辑的地方,我们就可以对方法执行前、后填充自己的逻辑了
注意: 这个类实例化的时候传了一个Object参数,这个就是上面的实现类,为什么要传进来?因为一个接口是可以有多个实现类的,你不传一个具体的实现类,我怎么知道要执行哪个实现类里面的方法呢?
public class DemoInvokeHandler implements InvocationHandler {
private Object object;
public DemoInvokeHandler(Object object){
this.object=object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 所以可以在这里 方法执行前写逻辑
System.out.println("方法执行前执行");
// 这个就是我们原本的方法执行
Object invoke=method.invoke(object,args);
// 所以可以在这里 方法执行后写逻辑
System.out.println("方法执行后执行");
return invoke;
}
}
像以上这样呢,整个接口中的方法都会被代理,如果我们只想代理某个方法呢?就需要对方法判断一下如:
这里只是对方法名过滤了,还可以结合注解、参数等过滤
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if(method.getName().equals("test1")){
// 所以可以在这里 方法执行前写逻辑
System.out.println("方法执行前执行");
// 这个就是我们原本的方法执行
Object invoke=method.invoke(object,args);
// 所以可以在这里 方法执行后写逻辑
System.out.println("方法执行后执行");
return invoke;
}else {
return method.invoke(object,args);
}
}
以上我们的准备工作就完成了,我们只需要在实际使用中,获取代理对象,执行代理对象即可,通过
Proxy.newProxyInstance获取代理对象,有三个传参:
// 获取代理对象
InvokeInterface invokeBean = (InvokeInterface) Proxy.newProxyInstance(InvokeBean.class.getClassLoader(),
new Class[]{InvokeInterface.class}, new DemoInvokeHandler(new InvokeBean()));
invokeBean.test1("test1",new int[]{1,2});
String test3 = invokeBean.test3("test3");
System.out.println(test3);
这个我们需要先导入依赖包
cglib
cglib
3.1
Cglib和JDK实现起来差不多,但是Cglib代理的是类,所以我们需要先准备个目标类
public class CglibTarget {
public void test(){
System.out.println("test 本方法执行");
}
}
同样的还需要自己的处理方法,这个要实现的接口就不一样。是Callback接口,而该接口有几种:
我们只看一下MethodInterceptor和InvocationHandler两种,其他毕竟用得少:
InvocationHandler:用法和JDK动态代理一样,参考JDK的即可
MethodInterceptor:
注意: 是net.sf.cglib.proxy.MethodInterceptor包下的,同时这个处理类实例化的时候就不需要再传参了
public class CglibProxy implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
// 所以可以在这里 方法执行前写逻辑
System.out.println("方法执行前执行");
// 这个就是我们原本的方法执行
Object o1 = methodProxy.invokeSuper(o, objects);
// 所以可以在这里 方法执行后写逻辑
System.out.println("方法执行后执行");
return o1;
}
}
Cglib的使用同样是需要先生成一个代理对象,一般是靠Enhancer.create() 方法,但该方法有几个重载,我们一个一个介绍
先是最简单也是最常用的
// MethodInterceptor 方式
CglibTarget cglibTarget = (CglibTarget) Enhancer.create(CglibTarget.class, new CglibProxy());
cglibTarget.test();
// InvocationHandler 方式 与JDK一样,不需要类加载器了
Interface cglibTarget = (Interface) Enhancer.create(Interface.class, new CglibProxy(new 实现类));
cglibTarget.test();
这个就比上面那个更厉害了,上面那个只是代理原有类里面的方法,这个可以对代理原有的类帮他实现接口,并实现接口逻辑,这等于一个类凭空多了几个方法出来,怎么用?
上述的目标类不需要改,处理方法需要改一下,然后新建一个接口:
// 我们新建一个接口不需要任何实现类
public interface TestTarget {
public void test1();
}
// 修改处理方法
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
// 这里新增对上面接口里面方法的处理,其他的不需要变
if(method.getName().equals("test1")){
// 这里可以实现那个接口方法的逻辑
System.out.println("这里写实现那个接口的逻辑方法");
return "我是那个接口返回的";
}else {
// 所以可以在这里 方法执行前写逻辑
System.out.println("方法执行前执行");
// 这个就是我们原本的方法执行
Object o1 = methodProxy.invokeSuper(o, objects);
// 所以可以在这里 方法执行后写逻辑
System.out.println("方法执行后执行");
return o1;
}
}
调用:
// 先用接口生成器 对我们要实现的接口做一个处理
InterfaceMaker interfaceMaker=new InterfaceMaker();
interfaceMaker.add(TestTarget.class);
Class aClass = interfaceMaker.create();
// 然后我们就可以正常的传参调用了
CglibTarget o = (CglibTarget)new Enhancer().create(CglibTarget.class, new Class[]{aClass},new CglibProxy());
// 类中方法正常调用
o.test();
// 接口方法调用需要用反射 因为毕竟那接口的方法不存在对象方法里面
Method test1 = o.getClass().getMethod("test1");
test1.invoke(o);
结果:
为了演示效果,我们新建一个处理类CglibProxyOther,上面的都不需要变
public class CglibProxyOther implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
if(method.getName().equals("test1")){
System.out.println("新建处理类的逻辑方法");
return "我是那个新建处理类返回的";
}else {
// 所以可以在这里 方法执行前写逻辑
System.out.println("新建处理类——方法执行前执行");
// 这个就是我们原本的方法执行
Object o1 = methodProxy.invokeSuper(o, objects);
// 所以可以在这里 方法执行后写逻辑
System.out.println("新建处理类——方法执行后执行");
return o1;
}
}
}
然后新增一个过滤选择器filter:
实现CallbackFilter接口即可,返回值是处理类数组的下标(我这里用方面名称来选择,实际还可以用其他)
public class CglibFilter implements CallbackFilter {
@Override
public int accept(Method method) {
// test方法用下标为0的处理类
if(method.getName().equals("test")){
return 0;
}
// 其他方法用下标为1的处理类
return 1;
}
}
调用:
InterfaceMaker interfaceMaker=new InterfaceMaker();
interfaceMaker.add(TestTarget.class);
Class aClass = interfaceMaker.create();
CglibTarget o = (CglibTarget)new Enhancer().create(CglibTarget.class, new Class[]{aClass},new CglibFilter(),new Callback[]{new CglibProxy(),new CglibProxyOther()});
o.test();
Method test1 = o.getClass().getMethod("test1");
test1.invoke(o);
结果: 很明显的看到test1方法走了第二个处理类
至此重载方法全介绍完毕!
到底用什么相信大家有选择了,如果没特殊需求,就直接JDK得了,有特殊需求不用Cglib,JDK能满足吗?至于效率,这种效率的差距都体现在一定量往上的程度,没到这个量无需考虑太多!