码迷,mamicode.com
首页 > 其他好文 > 详细

【AOP】借助容器将服务与代理类分离

时间:2015-05-29 21:47:28      阅读:215      评论:0      收藏:0      [点我收藏+]

标签:


我们所希望的AOP是这样的:


    技术分享


业务单独开发,服务也单独开发.将希望被切入的业务颗粒扔到容器中,通过AOP这种思想(AOP的实现有多种)将服务切进去,换句话说,就是在AOP提供的切面类上配置服务与业务间的切入关系,然后将业务和服务都分别交给容器管理.

 

原来我们一直把它做成了这样:

     技术分享


这种实现确实也能够满足业务和服务单独开发,但是AOP不是作为工作的bean存在,切面类不可复用,不灵活.

 

为了让系统更灵活,我们首先要把写死在代理类(切面类)中的服务分离出去.

 

问题一:现在业务和服务已经彻底分离,如何让二者在需要的时候联合起来?

 

问题二:当有多个服务同时要切入业务系统,各个服务的方法不能写到代理类即切面类里,切面如何被复用?

 

我们来看一下不借助任何框架的简单实现.

 

业务:

public class CourseManager {

	public void addCourse(){
		System.out.println("The course has been added successfully !");
	}

}


日志服务:


public class LogUtil {

	public void Info(){
		System.out.println("Info: this is Infolog.");
	}
}


封装服务的容器:


import java.lang.reflect.Method;
import java.util.HashMap;

/**
 * 日志,权限,工作流等类和方法的封装类
 * @author ghy
 * version 3.0.0 , 2015年5月25日 上午10:57:31
 */
public class ProxyMethods {

	private HashMap<String, Object> logBeans;

	private HashMap<String, String> logMethodBeans;
	
	public void writeLog(){
		try {
			
			for(HashMap.Entry<String,Object> entry : logBeans.entrySet()){
				String key =entry.getKey();
				Object value =entry.getValue();
				Method writeLogMethod=value.getClass().getMethod(logMethodBeans.get(key));
				writeLogMethod.invoke(value);
			}
			
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}
	
	public HashMap<String, Object> getLogBeans() {
		return logBeans;
	}

	public void setLogBeans(HashMap<String, Object> logBeans) {
		this.logBeans = logBeans;
	}

	public HashMap<String, String> getLogMethodBeans() {
		return logMethodBeans;
	}

	public void setLogMethodBeans(HashMap<String, String> logMethodBeans) {
		this.logMethodBeans = logMethodBeans;
	}
}


容器中定义了两个hashmap,分别是类和方法的集合,简单的实现只有一个日志类,这个类中只有一个Info()方法.而且它们保存的key值相同,我们遍历集合,得到这个类里面的方法.

 

代理类:


import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;


/**
 * 一个业务类,一个方法
 * 代理类,即AOP的切面类,连接核心业务类和日志等功能类的方法,实现了拦截
 * @author ghy
 * version 3.0.0 , 2015年5月25日 上午10:59:11
 */
public class CGLibDynamicProxy implements MethodInterceptor{

	//单例模式获得代理对象
	public static CGLibDynamicProxy instance=new CGLibDynamicProxy();
	
	private CGLibDynamicProxy(){
	
	}
	
	public static CGLibDynamicProxy getInstance(){
		return instance;
	}
	
	//持有对proxyMethod的引用
	private ProxyMethods proxyMethods;

	//泛型方法,得到代理类
	public <T> T getProxy(Class<T> cls){
		return (T)Enhancer.create(cls, this);
	}
	
	//拦截核心业务的方法,在核心业务方法执行前添加写日志的方法
	@Override
	public Object intercept(Object target, Method method, Object[] args,
			MethodProxy methodProxy) throws Throwable {
		
		proxyMethods.writeLog();
		Object result=methodProxy.invokeSuper(target, args);
		return result;
		
	}

	public ProxyMethods getProxyMethods() {
		return proxyMethods;
	}

	public void setProxyMethods(ProxyMethods proxyMethods) {
		this.proxyMethods = proxyMethods;
	}
}


实现原理是CGLib动态代理,代理类中持有对proxyMethod容器的引用,这里可以调用容器的方法,容器就是一个空壳子,在运行时具体执行的类和方法才被装载.

 

客户端:

public class Client {

	public static void main(String[] args){
		
		//定义两个hashmap分别盛放类和方法
		HashMap<String, Object> logBeans=new HashMap();
		
		HashMap<String, String> logMethodBeans=new HashMap();
		
		//将日志类添加到盛放类的hashmap,将写日志的方法添加到盛放方法的hashmap
		//两个hashmap内均有一个类和一个方法,key值相同
		logBeans.put("LogUtil", new LogUtil());
		
		logMethodBeans.put("LogUtil", "Info");
		
		//实例化一个类和方法的封装类的对象,将盛放日志类和写日志的方法的两个hashmap放到对象中
	    ProxyMethods proxyMethods=new ProxyMethods();
	    
	    proxyMethods.setLogBeans(logBeans);
	    proxyMethods.setLogMethodBeans(logMethodBeans);
	    
	    //实例化代理对象
	    CGLibDynamicProxy cglib =CGLibDynamicProxy.getInstance();
	    
	    //将对象和方法封装类的对象放到代理中
	    cglib.setProxyMethods(proxyMethods);
	    
	    //声明一个业务类对象,并获得它的代理
	    CourseManager courseManager=cglib.getProxy(CourseManager.class);
	    
	    //调用方法
	    courseManager.addCourse();	
	}	
}



客户端手动new了一个容器,将日志服务注册到容器中,实例化代理对象,把容器挂到代理对象上,然后获得添加课程业务类的代理,调用方法.

 

运行结果:


         技术分享

          如果我们希望在添加课程方法的后面切入日志方法,没关系,只要把容器的方法调用写在添加课程方法的后面就行了.类比springAOP的before,after,around等,我们这里都可以实现.另外要说的是,这只是写活了AOP的一个简单程序,还可以继续实现多个业务颗粒,多个服务,以及每个业务颗粒和服务中有多个类,每个类中有多个方法的例子.写代码和写文章是一样一样的,没有最好的代码只有更完善的代码.


【AOP】借助容器将服务与代理类分离

标签:

原文地址:http://blog.csdn.net/zhuanzhe117/article/details/46240715

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!