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

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基础上实现的技术。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值