您的位置:首页 > 编程语言 > Java开发

通过实例理解Spring的Bean工厂和AOP框架

2012-02-23 22:55 411 查看

一、需求设想

现在我有一个配置文件,里面配置了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...");

}

}

4)、config.properties文件
#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)、测试结果

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: