Spring AOP与动态代理

       

        刚接触动态代理模式的时候,感觉着东西确实有意思,但仔细想想貌似平常很少情况下会被使用。后来知道了Spring AOP的底层是采用动态代理实现的。

     

        项目中采用spring声明式的事务控制、确实能够感受到AOP的存在,也能隐约明白AOP的底层实现和动态代码有莫大的关系。JDK的动态代理主要涉及到java.lang.reflect包中的两个类:Proxy和InvocationHandler。其中InvocationHandler是一个接口,可以通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编织在一起。

 

        横切逻辑平时项目中出现的确实不多,但是某些场景下还是存在的。最典型的的例子便是事务控制,还有比如某些方法需要进行性能监控、某些方法需要进行用户合法性的验证、某些方法需要进行日志记录等。

        下面通过方法的性能监控横切逻辑作为例子,了解下动态代理的一些知识。

 

package proxy.train;

public class PerformanceMonitor {
	private static ThreadLocal<MethodPerformance> performanceRecord =
			new ThreadLocal<MethodPerformance>();
	
	private long begin;
	private long end;
	private String serviceMethod;
	
	public void begin(String method) {
		System.out.println("begin monitor...");
		begin = System.currentTimeMillis();
		this.serviceMethod = method;
	}
	
	public void end() {
		System.out.println("end monitor...");
		end = System.currentTimeMillis();
		long elapse = end -begin;
		
		System.out.println(serviceMethod + "花费" + elapse + "毫秒\n");
	}
}

           这是一个简单的性能监控横切逻辑类,当业务方法被调用的时候、将先运行该监控类的begin方法,当业务方法运行结束后将执行监控类的end方法,已获得业务方法的执行时间。

 

package proxy.train;

public class ServiceImpl implements Service{

	public void removeTopic(int topicId) {
		System.out.println("模拟删除Topic记录: " + topicId);
	
		try {
			Thread.sleep(60);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

	}
	
	public void removeForum(int forumId) {
		System.out.println("模拟删除Forum记录: " + forumId);
	
		try {
			Thread.sleep(80);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

	}
}

            上面是一个业务类,通过实现InvocationHandler接口的动态代理类、可以很好地将业务逻辑和横切逻辑组织在一起。

 

package proxy.train;

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

public class MyInvocationHandler implements InvocationHandler {
	private Object target;//目标业务类
	public void setTarget(Object target) {
		this.target = target;
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		PerformanceMonitor pm = new PerformanceMonitor();
		pm.begin(method.getName());
		Object result = method.invoke(target, args);//通过反射调用目标类的目标方法
		pm.end();
		return result;
	}

}

     

package proxy.train;

import java.lang.reflect.Proxy;

public class MainTest {
	
	public static void main(String[] args) {
		
		ForumService fs = new ForumServiceImpl();
		MyInvocationHandler handler = new MyInvocationHandler();
		handler.setTarget(fs);
		ForumService fs1 = (ForumService) Proxy.newProxyInstance(fs.getClass().getClassLoader(), fs.getClass().getInterfaces(), handler);
		fs1.removeTopic(1024);
		fs1.removeForum(13);
	}
	
}

       

 

         上面的动态代理方法很好地将业务逻辑与横切逻辑编织在了一起。但是上面的实现方式也存在非常大的几个缺陷:

    1、目标类的所有方法都被添加了横切逻辑,某些时候我们只想给部分特定的方法添加横切逻辑;

    2、采用了硬编码的方式指定了植入逻辑的植入点,即在业务目标方法的开始和结束处植入横切逻辑;

    3、我们手工编写代理实例的创建过程,为不同类创建代理时,需要分别编写相应的创建代码,无法通用。

         这三个问题在AOP中占用重要的地位,Spring AOP的主要工作就是围绕以上三点展开的:Spring AOP通过Pointcut(切点)指定在哪些类的哪些方法上植入横切逻辑,通过Advice(增强)描述横切逻辑和方法的具体植入点(方法前、方法后、方法两端等)。Spring通过Advisor(切面)将Pointcut和Advice两者组装在一起。通过Advisor的信息,Spring就利用JDK动态代理技术采用统一的方式为目标Bean创建植入的代理对象。

    

猜你喜欢

转载自lws-az201403181940.iteye.com/blog/2099766
今日推荐