昆明java培训
达内昆明广州春城路

18487146383

热门课程

昆明达内Java培训:java的动态代理

  • 时间:2016-10-21
  • 发布:昆明Java培训
  • 来源:达内新闻

基于昆明达内Java培训的老师上述静态代理的缺点,那么有没有一种方式,在有多个类需要代理时不创建等量的代理类呢,答案是可以的,使用动态代理即可,此处主要是JDK自带的动态代理,也可以使用cglib等方式实现,上一篇策略模式的文章中用到了动态代理,这里我就不再专门举例子,还是把上一篇中用到的例子解释清楚吧:

先简单回忆一下昆明达内Java培训的老师上一个使用动态代理的例子,首先有两种类型的策略,一种是国家规定的年假天数,一种是公司规定的年假天数,对应类型的策略类使用注解的方式区别,同时注解上还标明了对应的工作年限,下面我一种类型的策略贴一个策略类,其他的策略类一样:

@NationalRange(@ValidateRange(min=1,max=10))

public class FiveDays implements VacationDays{

@Override

public int getVacationDays() {

System.out.println("国家规定:工作1到10年,年假5天");

return 5;

}

}

@CompanyRange(@ValidateRange(min=2,max=5))

public class CompanyThreeDays implements VacationDays{

@Override

public int getVacationDays() {

System.out.println("在当前公司2年到5年,3天年假");

return 3;

}

}

然后在简单工厂中通过动态代理返回策略类:

public VacationDays create(int workYears,int owCompanyYears){

List<Class<? extends VacationDays>> list = new ArrayList<Class<? extends VacationDays>>();

for(Class<? extends VacationDays> cla : daysList){

Annotation range = handleAnnotation(cla);//获取到策略类上的注解

if(range instanceof NationalRange){//判断是否是国家规定的年假策略

NationalRange nrange = (NationalRange)range;

if(workYears >= range.value().min() && workYears < nrange.value().max()){

list.add(cla);

}

}else if(range instanceof CompanyRange){//判断是否是公司规定的年假策略

CompanyRange crange = (CompanyRange)range;

if(nowCompanyYears >= crange.value().min() && nowCompanyYears < crange.value().max()){

list.add(cla);

}

}

}  

//动态代理

return DaysProxy.getProxy(list);

}

然后是创建的代理类:

public class DaysProxy implements InvocationHandler{

private List<Class<? extends VacationDays>> list;

public DaysProxy(List<Class<? extends VacationDays>> list){

super();

this.list = list;

}

@Override

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

int result = 0;

if(method.getName().equals("getVacationDays")){

for(Class<? extends VacationDays> cla : list){

result += (int)method.invoke(cla.newInstance(), args);

}

System.out.println("年假总天数"+result);

return result;

}

return null;

}

public static VacationDays getProxy(List<Class<? extends VacationDays>> list){

return (VacationDays) Proxy.newProxyInstance(DaysProxy.class.getClassLoader(), new Class<?>[]{VacationDays.class}, new DaysProxy(list));

}

}

解释

动态代理是在运行期通过反射的方式生成代理类,并且生成代理类的字节码文件保存到本地,生成的代理类是java.lang.reflect.Proxy和你传入的接口的子类,因此在调用java.lang.reflect.Proxy的newProxyInstance方法生成代理类时,可以将生成的代理类转换成你调用上述方法时传入的任意接口,如上述代码片段中的getProxy(List> list)方法,其中传入newProxyInstance方法中的接口类型是VacationDays.class,因此就可以将生成的代理类转换成VacationDays类型;同样也可以转换成java.lang.reflect.Proxy类型,但是Proxy类型中都是静态方法,而且无法调用委托类中的方法,因此还是需要转换成传入的接口类型,也就是委托类的实现的接口,此外需要注意的一点是委托类必须是接口类型或者说实现了某个接口,否则会报不是接口的异常,虽然说一个类和一个接口中的方法完全一样,但是没有实现时也可以强转成功,但是在调用method的invoke方法时会出错,因为Method中并没有保存类的信息,保存的是接口的信息。

然后是关于invoke方法的调用,invoke方法接收三个参数,分别是代理类、委托类中的方法以及方法的参数列表,前面通过java.lang.reflect.Proxy类的静态方法newProxyInstance生成具体的代理类,然后在执行代理类中的方法时其实就是回调invoke方法,执行完成后返回具体的执行结果;

上面两段是原理性的东西,然后具体解释一下上面的代码,首先简单工厂中的create方法需要返回一个策略类,但是此时由于使用的是叠加策略,严格来说是需要返回两个策略类的,但是方法的返回值已经确定只能是一个策略类,这时候怎么办呢?使用动态代理的方式,返回一个代理类,这个代理类能同时处理处理两个策略类中的getVacationDays方法,那么OK,我们需要创建一个生成动态代理的类DaysProxy,这个类要实现java.lang.reflect.InvocationHandler接口,实现其中的invoke方法,在简单工厂类中将满足条件的策略类的class集合传递到代理生成类中,然后使用Proxy.newProxyInstance方法生成一个代理对象返回到简单工厂中,简单工厂再将这个代理类返回给客户端,客户端调用计算年假的方法时,代理类通过执行invoke方法返回对应的结果。

动态代理说明

动态代理这块目前以我的能力也只能分析到这里了,自己能看的明白,但是想把这个内容很有条例的分析出来却又不知道如何下手,本来想结合源代码仔细分析一下的,但是确实能力有限,源代码倒是能看懂,但是写就写不出来了,还需要继续努力呀。

动态代理的优/缺点

优点

动态代理在实现阶段也就是编译阶段,不需要关心代理类,因为代理类只有在运行期才动态的生成,可以同时代理多个实现了同一接口的委托类(特指JDK的动态代理,如果没有统一的接口,可以使用cglib实现动态代理);

缺点

使用动态代理的类需要实现同一接口;

由于在运行期动态生成代理类的字节码文件,效率上会稍慢一些;

代理模式总结

代理模式是一个结构型的设计模式,其主要的作用是用来达到功能复用的目的,比如静态代理可以拿来增强委托类的某些功能,或者说屏蔽掉委托类的某些功能;可以使用动态代理来达到实现AOP的目的,比如在具有统一接口的某些类的某些方法的前后添加上一些操作(使用JDK的动态代理),如果这些类没有统一的接口,那么可以使用cglib实现动态代理。

了解详情请登陆昆明达内Java培训官网(km.Java.tedu.cn)!

上一篇:Java培训:java的代理模式
下一篇:Java培训:服务器部署多个tomcat经验

昆明达内Java培训带你了解机器学习

中美it行业数据大pk

昆明达内java培训的面试问题你都掌握了吗

机器学习领域需要掌握什么

选择城市和中心
贵州省

广西省

海南省

扫一扫

了解更多干货