反射最大的价值就是用来写框架,下面贴出自己的3篇代码,模拟实现SPING框架的bean工厂,IOC,AOP。当然这里重点是在利用反射实现功能,为了图方便,我用的是Properties文件,关于XML后面会有专门的博客来整理,到时候整合相关的解析XML的代码就可以了。
1,通过反射,读取配置文件来管理bean
package linkin; import java.io.FileInputStream; import java.util.HashMap; import java.util.Map; import java.util.Properties; //这里就是通过反射,来获得对象的工厂 public class Linkin { // 定义一个对象池,前面是对象名,后面是实际对象 private Map<String ,Object> objectPool = new HashMap<String ,Object>(); // 定义一个创建对象的方法,该方法只要传入一个字符串类名,程序可以根据该类名生成Java对象 private Object createObject(String clazzName) throws Exception { // 根据字符串来获取对应的Class对象 Class<?> clazz = Class.forName(clazzName); // 使用clazz对应类的默认构造器创建实例 return clazz.newInstance(); } // 该方法根据指定文件来初始化对象池,它会根据配置文件来创建对象 public void initPool(String fileName) throws Exception { FileInputStream fis = null; try { fis = new FileInputStream(fileName); Properties props = new Properties(); props.load(fis); for (String name : props.stringPropertyNames())//返回此属性列表中的键集 { // 每取出一对key-value对,就根据value创建一个对象,调用createObject()创建对象,并将对象添加到对象池中 objectPool.put(name ,createObject(props.getProperty(name))); } } catch (Exception ex) { System.out.println("读取" + fileName + "异常"); } finally { if(null != fis) { fis.close(); } } } public Object getObject(String name) { // 从objectPool中取出指定name对应的对象。 return objectPool.get(name); } public static void main(String[] args) throws Exception { Linkin linkin = new Linkin(); linkin.initPool("Linkin.txt");//linkin=linkin.Linkin System.out.println(linkin.getObject("linkin")); } }
2,通过反射实现IOC注入功能
package linkin; import java.io.FileInputStream; import java.io.IOException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import java.util.Properties; public class Linkin { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } // 定义一个对象池,前面是对象名,后面是实际对象 private Map<String ,Object> objectPool = new HashMap<String ,Object>(); private Properties config = new Properties(); // 从指定属性文件中初始化Properties对象。 public void init(String fileName) throws Exception { FileInputStream fis = null; try { fis = new FileInputStream(fileName); config.load(fis); } catch (IOException ex) { System.out.println("读取" + fileName + "异常"); } finally { if(null != fis){ fis.close(); } } } // 定义一个创建对象的方法,该方法只要传入一个字符串类名,程序可以根据该类名生成Java对象 private Object createObject(String clazzName) throws Exception { // 根据字符串来获取对应的Class对象 Class<?> clazz =Class.forName(clazzName); // 使用clazz对应类的默认构造器创建实例,这一行道出了javabean的精髓,为什么javabean规范中要就有一个默认的无参的构造器 return clazz.newInstance(); } // 该方法根据指定文件来初始化对象池,它会根据配置文件来创建对象 public void initPool() throws Exception { for (String name : config.stringPropertyNames()) { // 每取出一对key-value对,如果key中不包含百分号(%) // 这个就标明是根据value来创建一个对象 // 调用createObject创建对象,并将对象添加到对象池中 if (!name.contains("%")) { objectPool.put(name , createObject(config.getProperty(name))); } } } // 该方法根据指定文件来初始化对象池,它会根据配置文件来创建对象 public void initProperty()throws Exception { for (String name : config.stringPropertyNames()) { // 每取出一对key-value对,如果key中包含百分号(%) // 即可认为该key是用于为对象的Field设置值, // %前半为对象名字,后半为Field名 // 程序将调用对应的setter方法来为对应Field设置值。 if (name.contains("%")) { // 将配置文件中key按%分割 String[] objAndProp = name.split("%"); // 取出需要设置Field值的目标对象 Object target = getObject(objAndProp[0]); // 该Field对应的setter方法名:set + "属性的首字母大写" + 剩下部分 String mtdName = "set" + objAndProp[1].substring(0 , 1).toUpperCase() + objAndProp[1].substring(1); // 通过target的getClass()获取它实现类所对应的Class对象 Class<?> targetClass = target.getClass(); // 获取该属性对应的setter方法,下面这一行道出了springIOC的精髓,为什么实现XML我们每次都要提供get和set方法,除了注解的哦 Method mtd = targetClass.getMethod(mtdName , String.class); // 通过Method的invoke方法执行setter方法,将config.getProperty(name)的属性值作为调用setter的方法的实参 mtd.invoke(target , config.getProperty(name)); } } } public Object getObject(String name) { // 从objectPool中取出指定name对应的对象。 return objectPool.get(name); } public static void main(String[] args)throws Exception { Linkin linkin = new Linkin(); linkin.init("Linkin.txt");//linkin=linkin.Linkin //linkin%name=LinkinPark... linkin.initPool(); linkin.initProperty(); linkin = (Linkin) linkin.getObject("linkin"); System.out.println(linkin.getName()); } }
3,通过反射实现AOP框架,并且跑了代理,(人为可以控制跑不跑代理)。
package linkin; import java.io.FileInputStream; import java.io.IOException; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.HashMap; import java.util.Map; import java.util.Properties; public class Linkin implements Person { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } //定义这个方法来作为测试 public void test() { System.out.println("这里是原始的方法"); } // 定义一个对象池,前面是对象名,后面是实际对象 private Map<String ,Object> objectPool = new HashMap<String ,Object>(); private Properties config = new Properties(); // 从指定属性文件中初始化Properties对象。 public void init(String fileName) throws Exception { FileInputStream fis = null; try { fis = new FileInputStream(fileName); config.load(fis); } catch (IOException ex) { System.out.println("读取" + fileName + "异常"); } finally { if(null != fis){ fis.close(); } } } // 定义一个创建对象的方法,该方法只要传入一个字符串类名,程序可以根据该类名生成Java对象 private Object createObject(String clazzName) throws Exception { // 根据字符串来获取对应的Class对象 Class<?> clazz = Class.forName(clazzName); // 使用clazz对应类的默认构造器创建实例,这一行道出了javabean的精髓,为什么javabean规范中要就有一个默认的无参的构造器 return clazz.newInstance(); } // 该方法根据指定文件来初始化对象池,它会根据配置文件来创建对象 public void initPool() throws Exception { for (String name : config.stringPropertyNames()) { // 每取出一对key-value对,如果key中不包含百分号(%),这个就标明是根据value来创建一个对象,调用createObject创建对象,并将对象添加到对象池中 // 如果他是我们自己定义的LinkinProxy,就说明这里是跑代理的,不然就是不跑代理的 String className = config.getProperty(name); if (!name.contains("%") && !name.contains(".")) { Object bean = createObject(className); if(bean instanceof LinkinProxy) { LinkinProxy linkinProxyBean = (LinkinProxy) bean; LinkinAdvice linkinAdvice = (LinkinAdvice) createObject(config.getProperty(name + ".advice")); Object target = createObject(config.getProperty(name + ".target")); initProperty(target); linkinProxyBean.setLinkinAdvice(linkinAdvice); linkinProxyBean.setTarget(target); bean = linkinProxyBean.getProxyBean(); } else { initProperty(bean); } objectPool.put(name , bean); } } } // 该方法根据指定文件来初始化对象池,它会根据配置文件来创建对象 public void initProperty(Object target)throws Exception { for (String name : config.stringPropertyNames()) { // 每取出一对key-value对,如果key中包含百分号(%) // 即可认为该key是用于为对象的Field设置值, // %前半为对象名字,后半为Field名 // 程序将调用对应的setter方法来为对应Field设置值。 if (name.contains("%")) { // 将配置文件中key按%分割 String[] objAndProp = name.split("%"); // 取出需要设置Field值的目标对象,这里加一个控制,如果他是代理的话,就不能从池里面去取le //Object target = getObject(objAndProp[0]); // 该Field对应的setter方法名:set + "属性的首字母大写" + 剩下部分 String mtdName = "set" + objAndProp[1].substring(0 , 1).toUpperCase() + objAndProp[1].substring(1); // 通过target的getClass()获取它实现类所对应的Class对象。 Class<?> targetClass = target.getClass(); // 获取该属性对应的setter方法,下面这一行道出了springIOC的精髓,为什么实现XML我们每次都要提供get和set方法,除了注解的哦 Method mtd = targetClass.getMethod(mtdName , String.class); // 通过Method的invoke方法执行setter方法,将config.getProperty(name)的属性值作为调用setter的方法的实参 mtd.invoke(target , config.getProperty(name)); } } } public Object getObject(String name) { // 从objectPool中取出指定name对应的对象。 return objectPool.get(name); } public static void main(String[] args)throws Exception { Linkin linkin = new Linkin(); linkin.init("Linkin.txt"); linkin.initPool(); Person huhu = (Person) linkin.getObject("XXX"); System.out.println(huhu.getClass()); huhu.test(); } } class LinkinProxy { private Object target;//原始对象 private LinkinAdvice linkinAdvice;//服务 public LinkinAdvice getLinkinAdvice() { return linkinAdvice; } public void setLinkinAdvice(LinkinAdvice linkinAdvice) { this.linkinAdvice = linkinAdvice; } public Object getTarget() { return target; } public void setTarget(Object target) { this.target = target; } public Object getProxyBean() { LinkinInvocationHandler linkinInvocationHandler = new LinkinInvocationHandler(); linkinInvocationHandler.setTarget(target); linkinInvocationHandler.setLinkinAdvice(linkinAdvice); Object proxyBean = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), linkinInvocationHandler); return proxyBean; } } //定义接口 interface Person { void test(); } interface LinkinAdvice { public void test(); public void test1(); } //定义服务1 class LinkinAdvice1 implements LinkinAdvice { public void test() { System.out.println("这里是第1个通用的方法。。。"); } public void test1() { System.out.println("这里是第2个通用的方法"); } } //定义服务2 class LinkinAdvice2 implements LinkinAdvice { public void test() { System.out.println("这里是第3个通用的方法。。。"); } public void test1() { System.out.println("这里是第4个通用的方法"); } } class LinkinInvocationHandler implements InvocationHandler { private Object target; private LinkinAdvice linkinAdvice;//服务 public Object getTarget() { return target; } public void setTarget(Object target) { this.target = target; } public LinkinAdvice getLinkinAdvice() { return linkinAdvice; } public void setLinkinAdvice(LinkinAdvice linkinAdvice) { this.linkinAdvice = linkinAdvice; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { linkinAdvice.test(); Object result = method.invoke(target, args); linkinAdvice.test1(); return result; } }
#一下配置文件的说明:要是直接生成原始对象就直接指定全限定类名就好了,要是想跑代理就指定下面那个名字,然后设置服务和原始对象# #下面的属性注入模拟了IOC功能,不管是代理对象还是原始对象,都可以把这个属性值注入,原始对象就是注入原始对象,代理对象就是注入到被代理的那个原始对象中# #XXX=linkin.Linkin ##以这个作为控制,要是得到的类放完反射属于这个类,那么就认为是要代理,不然就是不代理# XXX=linkin.LinkinProxy #模拟了属性注入,XML是通过自己的标签,这里我自己使用“%”模拟了下# XXX%name=LinkinPark... #这里是代理对象的服务,也就是AOP中插入的通用服务代码,可以随便切换,自己定义个服务,这里配上就可以用了# XXX.advice=linkin.LinkinAdvice2 #这里就是上面那个代理类的原始对象# XXX.target=linkin.Linkin