首页 > WEB开发 > 后台开发 > Spring AOP
2014
10-05

Spring AOP

10. Spring AOP11

AOP的核心和关键技术是代理,关于AOP和代理的知识参考《动态代理技术》一文。

一、基本知识点

1、静态代理 Vs. 动态代理

本小节的内容在《动态代理技术》一文更详细,在此仅列举一个例子,不过多赘述。

业务场景:从Dao层抽取事务管理的操作,封装到自定义Transaction类,并利用代理技术将事务处理切入到Dao操作前后。

1)静态代理:代理类由手工编写。

10. Spring AOP294

代理类(PersonDaoProxy)如下:

public class PersonDaoProxy implements PersonDao {
	private PersonDao dao;
	private Transaction transaction;

	public PersonDaoProxy(PersonDao dao, Transaction transaction){
		this.dao = dao;
		this.transaction = transaction;
	}

	public void save() {
		transaction.beginTransaction();
		dao.save();
		transaction.commit();
	}
}

静态代理模式的不足:

① 系统中有多少Dao(目标类),就得写多少proxy。

② 如果目标接口有方法的改动,则proxy也得做相应的修改。

静态代理只是提供了一个代理的思想,但是并不适合用在项目中。更多的还是用动态代理。

2)动态代理:代理对象在程序运行时动态产生(通过反射机制)

JDK中提供了一套基于接口的动态代理API,核心是Proxy类,该类用于产生代理对象(也可产生代理类)

public class PersonDaoTest {
	@Test
	public void testDynamicProxy(){
		PersonDao dao = new PersonDaoImpl();
		Transaction transaction = new Transaction();

		TransactionInterceptor interceptor = new TransactionInterceptor(dao,transaction);
		PersonDao proxy = (PersonDao) Proxy.newProxyInstance(dao.getClass().getClassLoader(), dao.getClass().getInterfaces(), interceptor);

		proxy.save();
	}
}
------------------TransactionInterceptor---------------------
public class TransactionInterceptor implements InvocationHandler {

	private Object target;
	private Transaction transaction;

	public TransactionInterceptor(Object target, Transaction transaction){
		this.target = target;
		this.transaction = transaction;
	}

	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		if(method.getName().equals("save")
			|| method.getName().equals("update")){
			transaction.beginTransaction();
			Object rtValue = method.invoke(target, args);
			transaction.commit();
			return rtValue;
		}
		return method.invoke(target, args);
	}
}

JDK动态代理的优点:动态的产生代理对象,所以只需用一个TransactionInterceptor就可以完成所有Dao操作的事务处理。

缺点是如果有些Dao操作不需事务处理,在invoke方法中进行判断也是件麻烦的事(如上面的代码只对save和update方法进行处理)。

2、基于接口的代理 Vs. 基于子类的代理

JDK动态代理(基于接口) Vs. CGlib生成代理(基于子类)

  • 当目标类实现了某个接口,就可以使用JDK的Proxy生成目标类的代理对象。
  • CGLIB可以生成目标类的子类,并重写父类非final修饰符的方法(功能增强)。

假设PersonDaoImpl没有实现任何接口,则可以用CGlib动态生成PersonDaoImpl的代理对象:

public class PersonDaoTest {
	@Test
	public void testCGlibProxy(){
		PersonDaoImpl dao = new PersonDaoImpl();
		Transaction transaction = new Transaction();

		TransactionInterceptor interceptor = new TransactionInterceptor(dao,transaction);
		PersonDaoImpl proxy = (PersonDaoImpl)interceptor.createProxy();

		proxy.save();
	}
}
------------------TransactionInterceptor---------------------
public class TransactionInterceptor implements MethodInterceptor {

	private Object target;
	private Transaction transaction;

	public TransactionInterceptor(Object target, Transaction transaction){
		this.target = target;
		this.transaction = transaction;
	}

	public Object createProxy(){
		Enhancer enhancer = new Enhancer();//该类用于生成代理对象(改写父类方法,相当于功能增强)
		enhancer.setSuperclass(target.getClass());//设置父类
		enhancer.setCallback(this);//设置回调为本拦截器(及代理对象的调用处理程序)

		return enhancer.create();//返回代理对象
	}

	/**
	 * 该方法的内容和jdk动态代理中的invoke方法的内容是一样的
	 */
	public Object intercept(Object arg0, Method method, Object[] args,
			MethodProxy arg3) throws Throwable {
		if(method.getName().equals("save")
			|| method.getName().equals("update")){
			transaction.beginTransaction();
			Object rtValue = method.invoke(target, args);
			transaction.commit();
			return rtValue;
		}
		return method.invoke(target, args);
	}
}

二、AOP中的概念

先看下面非常官方的定义,然后再结合前面的代码说明。

  • Aspect(切面):横切性关注点的抽象即为切面,它与类相似,只是两者的关注点不一样,类是对物体特征的抽象,而切面是横切性关注点的抽象。比较民间一点的解释就是“切入到系统中的一个方面”,见《动态代理技术》一文。
  • Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点,实际上joinpoint还可以是field或类构造器。
  • Pointcut(切入点):所谓切入点是指我们要对哪些joinpoint进行拦截的定义。
  • Advice(通知):所谓通知是指拦截到joinpoint之后所要做的事情,通知分为前置通知、后置通知、异常通知、最终通知和环绕通知。
  • Target(目标对象):代理的目标对象
  • Weave(织入):将aspects应用到target对象,即创建代理对象的过程。

以上面在PersonDaoImpl中切入事务的业务为例:

  • Transaction类就是切面;
  • Transaction中的方法:beginTransaction、commit就是通知;
  • PersonDaoImpl中的save方法需要事务处理,因此save方法就是连接点。
  • 在invoke(或intercept)方法中的判断就是切入点。

具体见下图标注:

10. Spring AOP4149

几点说明(需要完全理解):

① 通知就是切面中的方法(切面方法)

② 连接点就是目标类中需要被拦截的方法(目标方法)

③ 代理对象中的方法 = 通知 + 目标方法

④ 在实际开发中,通知和目标方法是完全松耦合的。

AOP出现的意义:

10. Spring AOP4269


留下一个回复

你的email不会被公开。