java动态代理
首先先上一个小例子运行起来看看什么是代理
首先是接口类
public interface JieKou {
public void show(String str);
}
实现类
public class Impl implements JieKou{
@Override
public void show(String str) {
System.out.println("这是impl的实现方法参数是:"+str);
}
}
代理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class DaiLi implements InvocationHandler {
Object obj = null;
@Override
//proxy 代理对象
//method:代理的方法对象
//args:方法调用时参数
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object show = method.invoke(obj , args);
after();
return show;
}
// 调用invoke方法之前执行
private void before() {
System.out.println("执行前....");
}
// 调用invoke方法之后执行
private void after() {
System.out.println("执行后....");
}
}
测试类
import java.lang.reflect.Proxy;
public class Test {
public static void main(String[] args) throws Exception, IllegalAccessException {
//创建代理类对象
DaiLi dl = new DaiLi();
//获取要被代理的class对象
Class clazz = Class.forName("daili.Impl");
//把被代理对象交给代理对象
dl.obj = clazz.newInstance();
//接口 获取 代理类的 实现,由JDK提供的Proxy得newProxyInstance方法实现
//第一个参数为被代理的对象
//第二个参数是被代理对象所实现的接口
//第三个参数是实现了InvocationHandler接口的对象,该类中要实现invoke()方法,也就是我们的代理类
JieKou jieKou = (JieKou) Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), dl);
String str = "待定";
//使用被实现的 接口
jieKou.show(str);
}
}
代理之后的运行结果

接下来是没有经过代理的运行结果

可以看出没有经过代理的方法是直接执行实现类中的方法,而经过代理的执行后的结果是带上我们自定义的两个方法的。这里我把代理理解为一个中间商,就像平时我们去买东西去厂里直接购买和去店里买的价格不一样,原因也是很简单,店家从厂里进货肯定便宜,但是他用进价直接卖给你他图什么,所以一般都会比进价要高,要有钱可赚。那现在代理就像这个中间商,我肯定有自己的目的才会代理,那么我就说一点简单的使用比如代理后我们就可以在这个方法的执行前后做一些操作比如做一个记录,这个方法执行了大概长时间,或者是这个方法什么时候执行了。
上面可以看出我每次使用代理都要重新写一套很不方便,接下来我就做一些改变。
我加上一个所谓的容器类
public class RongQi {
static Map map = new HashMap();
public static Map init() {
map.put("Impl", "daili.Impl");
map.put("ImplTow", "daili.ImplTow");
return map;
}
我们把要进行代理的类提前的定义好放到map中充当一个容器,然后再代理时我们从map中获取想要代理的类
public class Test {
public static void main(String[] args) throws Exception{
Map map = RongQi.init();
//创建代理类对象
DaiLi dl = new DaiLi();
//获取要被代理的class对象
//这进行了更改,这里依然还是有点死,其实可以作为参数传进来的。
Class clazz = Class.forName(map.get("ImplTow").toString());
//把被代理对象交给代理对象
dl.obj = clazz.newInstance();
//接口 获取 代理类的 实现,由JDK提供的Proxy得newProxyInstance方法实现
//第一个参数为被代理的对象
//第二个参数是被代理对象所实现的接口
//第三个参数是实现了InvocationHandler接口的对象,也就是我们的代理类,该类中要实现invoke()方法。
JieKou jieKou = (JieKou) Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), dl);
String str = map.get("ImplTow").toString();
//使用被实现的 接口
jieKou.show(str);
}
}

这里我把要被代理的类作为了参数想要代理哪个类直接更改参数即可,不用再重新写一套代码。但是这里有一个问题,因为我是用的是jdk的动态代理,他的缺陷是只能使用接口而且必须有接口。由于java的单继承,动态生成的代理类已经继承了Proxy类的,就不能再继承其他的类,所以只能靠实现被代理类的接口的形式。
这里就要说第二种动态代理方式CGLIB了,他解决了jdk动态代理必须要接口且只能是接口的问题,让实现类也能够使用代理,但是他的思路是对指定的类生成一个子类,覆盖其中的所有方法达到代理的效果,所以该类或方法不能声明final。因为这里主要是想搞明白动态代理是什么和大概的场景且网上有很多cglib的使用代码,这里就不写cglib的使用了。
为了更好的理解他们两个的思路,可以看一下我写的一个关于静态代理的demo https://www.cnblogs.com/dswa/p/15812684.html
总结:
动态代理有两种方式
1.jdk自带的代理方式
主要是用到了反射机制,缺点是只能使用接口,且必须有接口
2.cglib的代理方式

浙公网安备 33010602011771号