一、需求设想
现在我有一个配置文件,里面配置了Bean的相关信息,如bean的类名(包括包名)、代理工厂(主要负责产生代理类)、目标类(被代理的类)、业务织入接口(Advice)。然后通过BeanFactory来产生Bean的实例,如果配置文件中配置的Bean是ProxyFactoryBean的实例,我们则产生这个Bean一个代理类的实例,还可以通过此配置文件进行切换,是使用代理类还是使用目标类来完成相应的业务功能,该配置文件的格式如下:
图1-1
如图1-1中所示,beanName就是我们要通过Bean工厂动态产生的实例或代理类实例,如果配置文件中的beanName指定的是ProxyFactoryBean,则获得的实例则是根据beanName.target对应的类名,由ProxyFactoryBean产生一个代理类的实例,并由beanName.advice对应的Advice织入相应的业务功能到该目标类中。
二、功能实现
1、步聚:
BeanFactory即然是专门用来产生Bean的,那就必须得知道产生这些个Bean的配置文件在哪里?这个配置文件事是先由程序员配置好的。所以在初始化BeanFactory的时候,就必要要得到产生这些Bean的配置文件。
1)、创建BeanFactory的一个唯一的构造方法,接收一个InputStream参数,这个参数用于获得Bean的配置文件。初始化的时候,通过Properties对象加载这个配置文件。
2)、创建一个getBean方法,接收一个参数(类名),用于根据beanName动态创建该类的一个实例。该beanName就是配置文件中的beanName。
3)、使用Class.forName方法根据beanName产生一个Class字节码对象,并产生一个实例对象
4)、如果该实例对象是ProxyFactoryBean的实例,则返回由ProxyFactoryBean产生的一个代理类实例,并注入配置文件中beanName.advice对应的Advice,否则直接返回该实例。
2、代码实例
1)、BeanFactory类
package proxy.aopframework; import java.io.IOException; import java.io.InputStream; import java.util.Properties; import proxy.Advice; /** * Bean工厂,负责产生代理类或目标类的实例 */ public class BeanFactory<T> { private Properties props = new Properties(); /** * 初始化bean工厂,加载bean的配置文件,该配置文件是一个标准的Properties文件,该文件由Key=Value的格式组成 * @param inStream bean的配置文件 */ public BeanFactory(InputStream inStream) { try { props.load(inStream); } catch (IOException e) { e.printStackTrace(); } } /** * 获取一个Bean的实例 * @param beanName bean javabean的名称 * @return 根据配置文件,返回目标类或代理类的实例 * @throws ClassNotFoundException */ public T getBean(String beanName) throws ClassNotFoundException { String className = props.getProperty(beanName); Class clazz = Class.forName(className); T bean = null; try { bean = (T)clazz.newInstance(); if (bean instanceof ProxyFactoryBean) { ProxyFactoryBean proxyFactoryBean = (ProxyFactoryBean) bean; Advice advice = (Advice) Class.forName(props.getProperty(beanName + ".advice")).newInstance(); Object target = Class.forName(props.getProperty(beanName + ".target")).newInstance(); proxyFactoryBean.setAdvice(advice); proxyFactoryBean.setTarget(target); bean = (T)proxyFactoryBean.getProxy(); } } catch (Exception e) { e.printStackTrace(); } return bean; } }
2)、ProxyFactoryBean类
package proxy.aopframework; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import proxy.Advice; /** * 代理工厂,负责产生目标对象的代理类 */ public class ProxyFactoryBean { /** * 被代理的目标对象 */ private Object target; /** * 目标对象要插入的业务逻辑 */ private Advice advice; public Object getTarget() { return target; } public void setTarget(Object target) { this.target = target; } public Advice getAdvice() { return advice; } public void setAdvice(Advice advice) { this.advice = advice; } /** * 获得一个代理类对象 * @return */ public Object getProxy() { return Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object retVal = null; try { advice.doBefore(target, method, args); retVal = method.invoke(target, args); advice.doAfter(target, method, args, retVal); } catch (Exception e) { advice.doThrow(target, method, args, e); } finally { advice.doFinally(target, method, args); } return retVal; }} ); } }
3)、Advice接口和LogAdvice实现类
package proxy; import java.lang.reflect.Method; /** * aop接口,提供方法运行前、方法运行后、方法运行中产生Exception、方法最终运行代码 * */ public interface Advice { /** * 方法运行前 * @param target 被代理的目标对象 * @param method 被调用的方法 * @param args 方法的参数 */ public void doBefore(Object target, Method method, Object[] args); /** * 方法运行后 * @param target 被代理的目标对象 * @param method 被调用的方法对象 * @param args 方法的参数 * @param retVal 方法的返回值 */ public void doAfter(Object target, Method method, Object[] args, Object retVal); /** * 方法运行时产生的异常 * @param target 被代理的目标对象 * @param method 被调用的方法 * @param args 方法参数 * @param e 运行时的异常对象 */ public void doThrow(Object target, Method method, Object[] args, Exception e); /** * 最终要执行的功能(如释放数据库连接的资源、关闭IO流等) * @param target 被代理的目标对象 * @param method 被调用的方法 * @param args 方法参数 */ public void doFinally(Object target, Method method, Object[] args); } package proxy; import java.lang.reflect.Method; import java.util.Arrays; /** * 日志功能切入类 * @author 杨信 * */ public class LogAdvice implements Advice { long beginTime = System.currentTimeMillis(); @Override public void doBefore(Object target, Method method, Object[] args) { System.out.println(target.getClass().getSimpleName() + "." + method.getName() + "方法被调用,参数值:" + Arrays.toString(args)); } @Override public void doAfter(Object target, Method method, Object[] args, Object retVal) { long endTime = System.currentTimeMillis(); System.out.println(target.getClass().getSimpleName() + "." + method.getName() + "方法运行结束,返回值:" + retVal + ",耗时" + (endTime - beginTime) + "毫秒。"); } @Override public void doThrow(Object target, Method method, Object[] args, Exception e) { System.out.println("调用" + target.getClass().getSimpleName() + "." + method.getName() + "方法发生异常,异常消息:"); e.printStackTrace(); } @Override public void doFinally(Object target, Method method, Object[] args) { System.out.println("doFinally..."); } }
#beanName=java.util.ArrayList beanName=proxy.aopframework.ProxyFactoryBean beanName.advice=proxy.LogAdvice beanName.target=java.util.ArrayList #hashMap=java.util.HashMap hashMap=proxy.aopframework.ProxyFactoryBean hashMap.advice=proxy.LogAdvice hashMap.target=java.util.HashMap
5)、测试类AopFrameworkTest
package proxy.aopframework; import java.io.InputStream; import java.util.HashMap; import java.util.Map; public class AopFrameworkTest { public static void main(String[] args) throws ClassNotFoundException { InputStream inStream = AopFrameworkTest.class.getResourceAsStream("config.properties"); /*BeanFactory<ArrayList> beanFactory = new BeanFactory<ArrayList>(inStream); List list = beanFactory.getBean("ArrayList"); System.out.println(list.getClass().getName()); list.add("zhangsan");*/ BeanFactory<HashMap> beanFactory = new BeanFactory<HashMap>(inStream); Map map = beanFactory.getBean("hashMap"); System.out.println(map.getClass().getName()); map.put("name", "zhangsan"); System.out.println(map.size()); } }6)、测试结果