博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring之AOP面向切片
阅读量:6679 次
发布时间:2019-06-25

本文共 5745 字,大约阅读时间需要 19 分钟。

   一、理论基础:

    AOP(Aspectoriented programming)面向切片/服务的编程,在Spring中使用最多的是对事物的处理。而AOP这种思想在程序中很多地方可以使用的,比如说,对某些规则的验证,可以抽象封装到一个模块中,并在该模块中定义一定的使用规则,然后植入到原有的程序中,其实这就是面向切片。这个模块叫做Aspect,定义的规则是pointcut,具体的验证的实现是advice,植入的目标叫TargetObject,切入到目标中的方法叫做joinpint,植入的过程叫weave。

   

Advice在模块中关注点的具体位置有:前、后或者抛出   Before、After、Throw 三种:

Before Advice

代用之前的处理

After Advice

调用之后的处理

Throw Advice

调用的时候抛出的异常处理

二、实践:

    有了理论基础后,重点还是在程序中使用。下面的实例使用注解和配置两种方式,实现对添加用户的方法的验证服务的切入。

1、Anotation注解的方式:

1.首先定义业务逻辑接口UserManager类的方法:

public interface UserManager {	public void addUser(String username, String password);		public void delUser(int userId);		public String findUserById(int userId);		public void modifyUser(int userId, String username, String password);}

2.UserManagerImpl类定义接口的实现:

public class UserManagerImpl implements UserManager {	public void addUser(String username, String password) {				System.out.println("---------UserManagerImpl.add()--------");	}	public void delUser(int userId) {			System.out.println("---------UserManagerImpl.delUser()--------");	}	public String findUserById(int userId) {				System.out.println("---------UserManagerImpl.findUserById()--------");		return "张三";	}	public void modifyUser(int userId, String username, String password) {				System.out.println("---------UserManagerImpl.modifyUser()--------");	}}

3.SecurityHandler定义要切入的方法:

@Aspectpublic class SecurityHandler {			/**	 * 定义Pointcut,Pointcut的名称为addAddMethod(),此方法没有返回值和参数	 * 该方法就是一个标识,不进行调用	 */	@Pointcut("execution(* add*(..))")	private void addAddMethod(){};			/**	 * 定义Advice,表示我们的Advice应用到哪些Pointcut订阅的Joinpoint上	 */	@Before("addAddMethod()")	//@After("addAddMethod()")	private void checkSecurity() {		System.out.println("-------checkSecurity-------");	}		}

Anotation注解规则:

       @Aspect表示注解的类是抽象的服务方法模块;

@Pointcut定义服务的使用规则,也就是服务方法要应用到目标类中哪些方法上。

@Pointcut("execution(*add*(..))") 第一个*表示不论是否有返回值,所有以add开头的方法,不管是否有参数。

private voidaddAddMethod(){};该方法只是注解模式中一个空的方法体,是一个模式化的方法定义结构,该方法不能有返回值,不能有任何参数,也不能对其进行实现。在Advice中要使用该方法名的标识。

Advice注解checkSecurity()方法,表示该方法是具体的服务方法,使用注解的方式,Advice不出现,而是使用上面理论部分提到的使用@After、@Befor、@Throw来表示,同时要在Advice中关联pointcut中定义的规则。

4.Client客户端调用:

public class Client {	public static void main(String[] args) {		BeanFactory factory = new ClassPathXmlApplicationContext("applicationContext.xml");		UserManager userManager = (UserManager)factory.getBean("userManager");		userManager.addUser("张三", "123");	}}

    AspecJ是通过applicationContext.xml文件中的配置,依据SecurityHandler类中的Anotation规则,将服务方法切入到UserManagerImpl类中的方法中的,所以,在客户端使用的时候要通过工厂取得UserManager对象。

5.applicationContext.xml文件中注入AspectJ的AOP服务:

2、配置文件的方式

    注解的方式灵活性不够,不便于业务的修改,下面是使用配置文件的方式:

    接口和实现接口类的方法以及在客户端的调用都是一样的,这里略。

1.SecurityHandler类像其他普通类一样,定义服务的方法即可:

public class SecurityHandler {		private void checkSecurity() {		System.out.println("-------checkSecurity-------");	}		}

2.重点是applicationContext.xml文件的配置:

注意到:

1.      Pointcut的匹配规则很灵活,可以使用|| 也可以指定包下的类。

2.      采用配置文件的方法是将服务模块Aspect通过DI注入的方式

3.      配置文件的方式不同于注解的方式,不需要在配置文件中显式的启用AspectJ对Annotation的支持。

3、参数的传递:

       在Advice的方法中使用JoinPoint对象可以取得客户端传入的参数值和调用的方法名:

public class SecurityHandler {		private void checkSecurity(JoinPoint joinPoint) {		for (int i=0; i

4、使用CGLIB的方式:

       如果UserManagerImpl不是实现UserManager接口,那么就需要使用CGLIB的方式,这时候工厂返回的不是UserManager接口对象。

1.UserManagerImpl类:

public class UserManagerImpl {	public void addUser(String username, String password) {				System.out.println("---------UserManagerImpl.add()--------");	}	public void delUser(int userId) {				System.out.println("---------UserManagerImpl.delUser()--------");	}	public String findUserById(int userId) {				System.out.println("---------UserManagerImpl.findUserById()--------");		return "张三";	}	public void modifyUser(int userId, String username, String password) {				System.out.println("---------UserManagerImpl.modifyUser()--------");	}}

2.客户端Client:修改返回值

public class Client {	public static void main(String[] args) {		BeanFactory factory = new ClassPathXmlApplicationContext("applicationContext.xml");				//UserManager userManager = (UserManager)factory.getBean("userManager");		UserManagerImpl userManager = (UserManagerImpl)factory.getBean("userManager");		userManager.addUser("张三", "123");			}}

这里需要注意的是:

    如果UserManagerImpl实现了UserManager接口,那么默认情况下,AspectJ采用jdk的动态代理,返回的是UserManager接口的动态代理对象;

    如果UserManagerImpl不是实现了UserManager接口这种方式,那么,AspectJ就会使用CGLIB的方式返回UserManagerImpl的一个CGLIB对象。

Jdk的动态代理和CGLIB实现机制的区别:

    Jdk基于接口实现:JDK动态代理对实现了接口的类进行代理

CGLIB基于继承:CGLIB代理可以对类代理,主要对指定的类生成一个子类,因为是继承,所以,目标类最好不要使用final声明。

    通常情况下,鼓励使用jdk代理,因为业务一般都会抽象出一个接口,而且不用引入新的东西。

如果是遗留的系统,以前没有实现接口,那么只能使用CGLIB

三、对比动态代理的实现服务切入:

动态代理的实现:接口和实现的方法不变,这里代码略。

1.动态代理类SecurityHandler:

public class SecurityHandler implements InvocationHandler {		private Object targetObject;		public Object createProxyInstance(Object targetObject) {		this.targetObject = targetObject;		return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), 							   targetObject.getClass().getInterfaces(), 							   this);	}		public Object invoke(Object proxy, Method method, Object[] args)			throws Throwable {		checkSecurity();				//调用目标方法		Object ret = method.invoke(targetObject, args);				return ret;	}		private void checkSecurity() {		System.out.println("-------checkSecurity-------");	}		}

2.客户端Client:

public class Client {	public static void main(String[] args) {		SecurityHandler hander = new SecurityHandler();		UserManager useraManager = (UserManager)hander.createProxyInstance(new UserManagerImpl());		useraManager.addUser("张三", "123");	}}

对比Spring的IOC和AOP,动态代理有几点是不同的:

1.动态代理使用new的方式创建接口的代理服务类。

2.代理类中将需要添加将服务方法植入到目标类方法中的代码。

3.需要在客户端维护接口类的实现,不够灵活。

四、结尾感触:

    Aop面向切片(服务)的编程时一种思想,在学习框架使用的时候,更应该学习这种设计思路,这是架构的基础,也是灵活架构的灵魂所在。

 

你可能感兴趣的文章
twitter storm源码走读之4 -- worker进程中线程的分类及用途
查看>>
apache + tomcat 集群
查看>>
C# ComboBox自动完成功能的示例
查看>>
VC++6.0和VS2005在编写MFC应用程序时,操作方面的差异
查看>>
从tableview中拖动某个精灵
查看>>
AE读取CAD图层包括注记
查看>>
误区30日谈16-20
查看>>
【ASP.NET Web API教程】6.4 模型验证
查看>>
Android 实现书籍翻页效果----完结篇
查看>>
JS实现页面打印
查看>>
广州市例外服饰有限公司_百度百科
查看>>
2014年3月新鲜出炉的最佳 JavaScript 工具库
查看>>
Android特性与系统架构
查看>>
java基础学习总结——Object类
查看>>
(转)2009-05-25 22:12 Outlook2007选择发送帐号
查看>>
WPF合并资源字典
查看>>
SPOJ 3273 - Order statistic set , Treap
查看>>
samba客户端配置及实例应用详解
查看>>
设计模式 -- 单例模式(Java&&PHP)
查看>>
安卓高手之路之 WindowManager
查看>>