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

Spring AOP(面向切面编程)【Spring AOP的技术基础】

2014-07-30 15:46 363 查看
Spring框架的AOP组件基于JDK的动态代理或者CGLIB代理实现,

其中JDK动态代理是使用较多的技术,动态代理是面向对象的代理(proxy)模式(GoF23)的一种动态实现。

代理模式
代理模式是一种结构型设计模式。当客户端不想直接调用主题对象,而希望在主题对象的行为前后加上预处理或者后续处理时,则可以使用代理模式。

代理模式中往往包含以下三种角色:

1、主题抽象类(Subject)

abstract public class Subject{
abstract public void request();
}


主题抽象类中定义了主题对象的行为,上述主题抽象类定义了主题对象的request行为。

2、实际主题类(RealSubject)

public class RealSubject extends Subject{
public RealSubject(){	}
public void request(){
System.out.println("From real subject.")
}
}
实际主题类继承了抽象主题类Subject,实现了抽象主题类中的行为request,实际主题类即AOP中的目标对象。
3、代理类(ProxySubject)

public class ProxySubject extends Subject{
private RealSubject realSubject;
public ProxySubject(){
}
public void request(){
preRequest();
if(realSubject==null){
realSubject = new RealSubject();
}
realSubject.request();
postRequest();
}
private void preRequest(){
//something you want to do before requesting
}
private void postRequest(){
//something you want to do after requesting
}
}
代理类继承了抽象主题类,同时关联了实际主题类。

代理类中定义了preRequest和postRequest方法,对实际主题类中的request方法实施了控制。

代理类对应Spring AOP中的ProxyFactoryBean类,用来生成代理对象,代理对象将Advice织入,从而对目标对象的方法进行了控制。

动态代理
动态代理是在运行时实现代理模式的方法,Java的JDK对其进行了实现。

JavaSE中实现动态代理的主要类有两个,如下所述:

1、java.lang.reflect.Proxy类,该类中提供获得代理类对象的方法

newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
该方法能够返回代理对象。

2、java.lang.reflect.InvocationHandler接口,该接口中提供了invoke方法,能够调用代理对象的方法。

package proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Date;

import log.Logger;

import org.apache.commons.dbcp.BasicDataSource;

import service.CustomerServiceImpl;
import dao.Impl.CustomerDAOImpl;

public class package proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Date;

import log.Logger;

import org.apache.commons.dbcp.BasicDataSource;

import service.CustomerServiceImpl;
import dao.Impl.CustomerDAOImpl;

public class CustomerServiceInvocationHandler implements InvocationHandler {

<span style="white-space:pre">	</span>@Override
<span style="white-space:pre">	</span>public Object invoke(Object proxy, Method method, Object[] args)
<span style="white-space:pre">			</span>throws Throwable {
<span style="white-space:pre">		</span>BasicDataSource dataSource = new BasicDataSource();
<span style="white-space:pre">		</span>dataSource.setDriverClassName("com.mysql.jdbc.Driver");
<span style="white-space:pre">		</span>dataSource.setUrl("jdbc:mysql://localhost:3306/mldn");
<span style="white-space:pre">		</span>dataSource.setUsername("root");
<span style="white-space:pre">		</span>dataSource.setPassword("password");
<span style="white-space:pre">		</span>dataSource.setMaxActive(10);
<span style="white-space:pre">		</span>dataSource.setInitialSize(2);
<span style="white-space:pre">		</span>CustomerDAOImpl dao = new CustomerDAOImpl();
<span style="white-space:pre">		</span>dao.setDataSource(dataSource);
<span style="white-space:pre">		</span>CustomerServiceImpl service = new CustomerServiceImpl();
<span style="white-space:pre">		</span>service.setDao(dao);
<span style="white-space:pre">		</span>Logger.log(method.getName()+" : "+new Date());
<span style="white-space:pre">		</span>return method.invoke(service, args);
<span style="white-space:pre">	</span>}

}


上述代码中的invoke方法,创建了CustomerServiceImpl类的实例service,然后向日志文件中添加日志信息,

最后使用method。invoke(service,args)调用了service实例的方法。

在invoke方法中,可以根据实际需要对目标类CustomerServiceImpl的方法实施控制,例如上述代码中使用Logger.log实现了日志功能。

完成CustomerServiceInvocationHandler类后,可以使用Proxy类生成代理对象,代码如下:

package test;

import java.lang.reflect.Proxy;

import proxy.CustomerServiceInvocationHandler;
import service.CustomerService;

public class TestProxy {

public static void main(String[] args) {
CustomerService serviceProxy=(CustomerService) Proxy.newProxyInstance(CustomerService.class.getClassLoader(), new Class[]{CustomerService.class}, new CustomerServiceInvocationHandler());
System.out.println(serviceProxy.login("tom", "tom"));
}

}
上述代码中,使用Proxy类中的newProxyInstance方法返回CustomerServiceImpl的代理对象,代理对象的类型就是CustomerService接口类型。

然后通过代理对象调用login方法,运行后将在日志文件中记录如下信息:

Wed Jul 30 16:22:41 CST 2014: login : Wed Jul 30 16:22:41 CST 2014


同事将在控制台打印输出如下信息:

invoke login...
true


Spring框架在动态代理的基础上,进一步使用了IoC容器生成代理对象,而不需要实现InvocationHandler接口,从而实现了Spring框架的AOP编程思想。

可见,Spring的AOP框架也是基于IoC基础上实现的技术。

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