动态代理及反射在工厂模式上的应用
2017-10-01 14:57
375 查看
前言
之前为读者讲解过代理机制的操作,但是讲解的代理设计属于静态代理,因为每一个代理类只能为一个接口服务,这样一来程序开发中必然会产生过多的代理。最好的做法是可以通过一个代理类完成全部的代理功能,那么此时就必须使用动态代理完成。在Java中要想实现动态代理机制,则需要java.lang.reflect.InvocationHandler接口和java.lang.reflect.Proxy类的支持。
InvocationHandler接口的定义如下:
public interface InvocationHandler{ public Object invoke(Object proxy,Method method,Onject[] args)throws Throwable }
在此接口中只定义了一个invoke()方法,此方法中有三个参数,其参数的意义如下。
Object proxy :被代理的对象
Method method :要调用的方法
object args[]: 方法调用时所需要的参数。
Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态的生成实现类。Proxy类提供了如下的操作方法:
public static Object newProxyInstance(ClassLoader loader, Class<?> [] interface,invocationHandler h)throws IllegalArgumentException
通过newProxyInstance()方法可以动态地生成实现类.
关于类加载器
在Proxy类的newProxyInstance()方法中需要一个ClassLoader类的实例,ClassLoader实际上对应的是类加载器,在Java中主要有以下3种类加载器。Bootstrap ClassLoader: 此加载器采用C++编写,一般开发中是看不到的
Extension ClassLoader: 用来进行扩展类的加载,一般对应的是jre\lib\ext目录中的类
AppClassLoader: 加载classpath指定的类,是最常使用的一种加载器。
如果要完成动态代理,首先定义一个InvocationHandler接口的子类,已完成代理的具体操作。
定义MyInvocationHandler的类
package org.ljz.dynaproxydemo; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class MyInvocationHandler implements InvocationHandler{ private Object obj; //真实主题 public Object bind(Object obj){ //绑定真实操作主题 this.obj=obj; return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass.getInstance(),this); //取得代理对象 } public Object invoke(Object proxy,Method method, Object[] args)throws Throwable{ //动态调用方法 Object temp=method.invoke(this.obj,args); //调用方法,传入真实主题和参数 return temp; //返回方法的返回信息 } }
在MyInvocationHandler类的bind()方法中接受被代理对象的真实主题实现,之后覆写InvocationHandler接口中的invoke()方法,完成具体的方法调用。
定义接口
package org.ljz.dynaproxydemo; public interface Subject{ //定义Subject接口 public String say(String name,int age); //定义抽象方法say
定义真实主题实现类
package org.ljz.dynaproxydemo; public class ReaSubject implements Subject{ //真实实现类 public String say(String name,int age){ //覆写say()方法 return "姓名:"+name+",年龄:"+age; //返回信息 } }
以上定义了接口及真实主题类,这样在操作时直接将真实主题类的对象传入到MyInvocationHandler类的bind()方法中即可。
测试动态代理
package org.ljz.demo.dynaproxydemo; public class DynaProxyDemo{ public static void main(String[] args){ MyInvocationHandler handler=new MyInvocationHandler();//实例化代理操作类 Subject sub=(Subject)handler.bind(new RealSubject());//绑定对象 String info=sub.say("ljz",30); //通过动态代理调用方法 System.out.println(info); //信息输出 } }
程序运行结果:
姓名: ljz, 年龄: 23
从程序运行的结果来看,完成的功能与之前的静态代理操作没有什么不同,所以在一般的开发中很少用到这种动态代理机制,但是在编写一般的底层代码或使用一些框架(如Spring Framework)时这种动态代理模式就比较正常了。
工厂设计模式
将反射用用在工厂设计模式上
工厂设计模式在实际开发中使用的非常多,之前读者已经学习过简单的工厂模式,通过简单的工厂设计模式可以达到类的解耦目的,但是之前的工厂设计模式依然存在问题,那就是在增加一个子类时都需要修改工厂类,这样肯定是很麻烦的。学习完反射机制之后,实际上,此时就可以通过反射机制来改善工厂类,让其在增加子类时可以不用做任何的修改,就可以到达功能的扩充,代码如下所示:使用反射完成工厂设计
package org.ljz.factorydemo01; interface Fruit{ //水果接口 public void eat(); //吃水果 } class Apple implements Fruit{ //定义苹果 public void eat(){ //覆写抽象方法 System.out.println("吃苹果"); } } class Orange implements Fruit{ //定义橘子 public void eat(){ //覆写抽象方法 System.out.println("吃橘子"); } } class Factory{ public static Fruit getInstance(String className){ //取得接口实例 Fruit fruit=null; //定义接口对象 try{ fruit=(Fruit)Class.forName(ClassName).newInstance(); //实例化对象 }catch(Exception e){ e.printStackTrace(); } return fruit; } } public class FactoryDemo01{ public static void main(String[] args){ //通过工厂类取得接口实例,传入完整的包.类名称 Fruit f=Factory.getInstance("org.ljz.demo.factorydemo01.Apple"); if(f!=null){ //判断是否取得接口实例 f.eat(); } } }
程序的运行结果:
** 吃苹果
以上的工厂操作类中使用了反射操作取得Fruit实例,这样无论增加多少个子类,工厂类都不用做任何的修改
结合属性文件的工厂模式
以上程序虽然可以通过反射取得接口的实例,但是在操作时需要传入完整的包.类名称,而且用户也无法知道一个接口有多少个可以使用的子类,所以此时可以通过属性文件的形式配置所有的子类信息。属性文件fruit.properties
apple=org.ljz.factorydemo02.Apple
orange=org.ljz.factorydemo02.Orange
在属性文件中使用apple和orange表示完整的包.类 名称,这样在使用就可以直接通过属性名称即可。
属性操作类
class Init{ //定义初始化操作类 public static Properties getPro(){ Properties pro=new Properties(); //实例化属性类 File f=new File("d:\\fruit.properties"); //找到属性文件 try{ if(f.exists()){ //属性文件中存在 pro.load(new FileInputStream(f)); //读取属性 }else{ pro.setProperty("apple","org.ljz.factorydemo02.Apple"); pro.setProperty("Orange","org.ljz.factorydemo02.Orange"); pro.store(new FileOutputStream(f),"FRUIT CLASS"); } }catch(Exception e){ e.printStackTrace(); } return pro; } }
此类中的主要功能是取得属性文件中的配置信息,如果属性文件爱你不存在,则创建一个新的,并设置默认值。
测试程序
public class FactoryDemo02{ public static void main(String[] args){ Properties pro=Init.getPro(); //初始化属性类 //通过工厂类取得接口实例,通过属性的key传入完整的包.类名称 Fruit f=Factory.getInstance(pro.getProperty("apple")); if(f!=null){ //判断是否取得接口实例 f.est(); //调用方法 } } }
在通过工厂类取得接口实例时,直接输入属性的key就可以找到完整的包.类名称,已达到对象的实例化功能。
在本程序中可以发现,程序很好地实现了代码与配置的分离。通过配置文件配置要使用的类,之后通过程序读取配置文件,已完成具体的功能,如图所示,当然程序完成的前提是基于接口,所以接口在实际开发中的用处是最大的。
总结
至此,关于Java反射相关的基础部分已经介绍完毕,还有许多反射更深层次的应用,欢迎大家一起学习交流!相关文章推荐
- 模拟实现Struts拦截器-蕴含着代理模式,AOP,工厂模式,依赖注入,Java 反射,动态构造等机制
- 15. JAVA 反射机制 Part 2(动态代理、类的生命周期、工厂设计模式) ----- 学习笔记
- 动态代理,工厂模式和反射技术
- Aop应用原理 JDK动态代理、代理模式与反射
- Java基础之反射及动态代理,反射实现工厂模式
- 反射实现 AOP 动态代理模式(Spring AOP 的实现 原理)
- 反射在工厂模式上的应用
- 反射实现 AOP 动态代理模式(Spring AOP 的实现 原理) --转
- 结合属性文件的工厂模式(java反射的应用)
- 反射实现 AOP 动态代理模式(Spring AOP 的实现原理)
- 代理模式【介绍、静态代理、动态代理、入门、应用】
- (尚硅谷)21 反射的应用-动态代理-AOP代理的实现
- 反射实现 AOP 动态代理模式(Spring AOP 的实现 原理)
- 反射实现 AOP 动态代理模式(Spring AOP 的实现 原理)
- 反射实现 AOP 动态代理模式(Spring AOP 的实现 原理)
- 反射实现 AOP 动态代理模式(Spring AOP 的实现 原理)
- 【Java EE 学习 24 下】【注解在数据库开发中的使用】【反射+注解+动态代理在事务中的应用service层】
- 设计模式之观察者与动态代理的结合应用
- 关于动态代理---模板方法模式,工厂模式,依赖倒转
- 设计模式的应用-动态代理实现事务控制