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

学习笔记--代理与AOP及实现类似SPRING的可配置的AOP框架

2013-10-30 20:37 986 查看

摘要:

首先由交叉业务引出面向方面编程AOP(Asbect ori Programming)和代理、动态代理然后描述如何在java中实现代理,最后描述如何使用代理实现类似SPRING的框架。

1.交叉业务的概念、AOP的思想以及实现技术代理

在实际的开发中经常会碰到为多个实现了同一接口的类的各个方法添加一些系统功能例如:日志、计算方法的运行时间、事务、异常处理等功能,我们可以编写一个类,该类和原始的类实现相同的接口,这个类中的每个方法调用原始类中的对应方法并加上我们所需的系统功能。可以用如下的代码表示:

class X{
public void show();
}
class XProxy{
public void show(){
stattime//记录开始时间
x.show();
endtime;//记录结束时间
};
}


我们不需要将记录时间的代码放在类x的show方法里面,放在外面会有一样的效果,AOP要解决的一个问题是将交叉业务模块化,而将系统功能代码放在方法外面提供了模块化的基础。

2.动态代理

如果我们有成百上千的类需要加上系统功能,则按照我们上面的说法不是要每个类编写一个代理类啊,这是不现实的那么如何解决这个问题呢?

此时静态代理不能满足我们的需求了,java中提供了动态生成类的技术,为我们的动态代理提供了基础

1.jvm可以动态的生成一个类,而这 个类必须实现一个或者多个接口,所以生成的类只能作为实现了相同接口的类的代理

2.CGLIB库可以实现动态生成一个类的子类,这个子类可以作为父类的动态代理

下面主要记录如何使用java.lang.reflect.Proxy和InvocationHandler及他们的原理。

下面以为ArrayList中实现Collection接口的方法添加系统功能为例说明,生成代理类对象代码如下:

Collection proxyBean = (Collection)Proxy.newProxyInstance(Collection.class.getClassLoader(),new Class[]{Collection.class},new Invocation(){

private ArrayList al = new ArrayList();

public Object invoke(Object proxy,Method method,Object[] args){

//方法调用之前系统功能添加到这里

Object  retVal = method.invoke(al,args);

//此处也可也添加系统功能

return retValue;

}

});


生成时主要参数:接口和InvocationHandler对象

生成代理对象的原理大致如下:首先根据传递的接口动态的为类生成对应的方法,在每个方法中调用InvocationHandler的invoke方法传递的参数分别是当前对象、当前方法、当前方法的参数,所以实现代理功能的核心就是InvocationHandler的invoke方法,只要在这个方法中人添加我们的系统功能即可。

到了这里还有一个疑问,代理对象是动态生成了,但是依然是我们编写代码实现的啊,没有实现动态代理的预期功能啊?

知道动态代理的使用和原理之后下面记录如何实现我们的预期功能:不需要手动的为每个类编写代理类(模拟spring)。

我们需要修改上面生成代理的代码,让变得更通用,代码如下:

public class ProxyFactoryBean {

private Advice advice = null;
private Object target = null;

public Advice getAdvice() {
return advice;
}

public void setAdvice(Advice advice) {
this.advice = advice;
}

public Object getTarget() {
return target;
}

public void setTarget(Object target) {
this.target = target;
}

public Object getProxy(){
return Proxy.newProxyInstance(this.target.getClass().getClassLoader(), this.target.getClass().getInterfaces(), new InvocationHandler() {
//final Advice advice = this.advice;
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
ProxyFactoryBean.this.advice.before();//注意这里添加this就出错了
Object retVal = method.invoke(target, args);
ProxyFactoryBean.this.advice.after();
return retVal;
}
});
}

}

public class BeanFactory {

private Properties props = null;
public BeanFactory(InputStream ins){

this.props = new Properties();
try {
this.props.load(ins);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public Object getBean(String name){

Object bean = null;

try {
bean = Class.forName(this.props.getProperty(name)).newInstance();
if(bean instanceof utils.ProxyFactoryBean){
utils.ProxyFactoryBean temp = (utils.ProxyFactoryBean)bean;
temp.setAdvice((Advice)Class.forName(this.props.getProperty(name+".advice")).newInstance());
temp.setTarget(Class.forName(this.props.getProperty(name+".target")).newInstance());
bean = temp.getProxy();
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return bean;
}
}


首先说明下Advicce,是所有要实现系统功能类要实现的一个该借口包含start()和end()方法这2个方法分别是调用方法之前和调用方法之后会执行的方法。原理及实现过程如下图:



总结

虽然代理可能在实际的开发过程中不会使用到,但他是SPRING等AOP框架的基础,只要理解了这个知识点,有利于加强对SPRING的理解,减少了学习成本。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐