一、需求设想
现在我有一个配置文件,里面配置了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)、测试结果