• 反射应用--IOC和AOP




    反射最大的价值就是用来写框架,下面贴出自己的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
      


  • 相关阅读:
    BrowserSync,自动刷新,解放F5,去掉更新提示
    js获取手机系统语言
    块元素,行内元素,行内块区别
    原生js判断某个元素是否有指定的class名的几种方法
    如何实现调用console.log(‘good’.repeat(3))时输出goodgoodgood?
    数组如何去除重复数据,只保留一条
    Sentinel笔记-Flow流控规则
    sentinel笔记 NodeSelectorSlot,ClusterBuilderSlot
    Sentinel笔记--Slotchain
    Sentinel笔记-核心类
  • 原文地址:https://www.cnblogs.com/LinkinPark/p/5233119.html
Copyright © 2020-2023  润新知