Spring中的代理模式 AOP Annotation实现方法

        之前我们有讲过代理模式和动态代理,其实在Spring中的AOP就是一种动态代理的体现。今天我们的话题就是Spring中的代理模式-AOP。
       
        什么是AOP呢?AOP为Aspect Oriented Programming的缩写,意为:面向切面编程(也叫面向方面),可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。

        他的好处很多,比如说有人说他可以让我们 减少很多重复代码,例如,我们的日志类,专用于写日志,但是很多日志都是相同的,方法开始,方法结束,方法异常,等等等等。AOP能够很轻松实现切面介入,只需要写一个方法,可以在所有需要用到的地方加入该切面类来做日志。他还有一个很大的优点,就是它极大的 降低了程序的耦合度。不管日志,还是开关数据库,都不是我这个业务本该有的东西,只能说是辅助方法而已。而将这些辅助方法写在切面类中,可以降低程序的耦合度,让对象类保持了他该有的一个完整性。

        我们今天的话题是,怎样用Annotation实现Spring的AOP。首先,我们需要在Spring的配置文件里加入这么一段话:
        <aop:aspectj-autoproxy />

        这样,Spring框架就支持aspectj了。了解的童鞋都知道,aspect是方面编程的jar包。所以我们还需要在项目中导入aspectjrt-1.2.jar和aspectjweaver-1.6.2.jar这两个包,第一个包顾名思义,是aspectj的runtime,即运行所需的包。第二个包是我们开发需要的包,weaver是编织者的意思,这里的意思即将切面方法织入我们的对象中。这里提供了maven导入两个包的配置,在pom.xml中加入下面这段依赖:
		<dependency>
			<groupId>aspectj</groupId>
			<artifactId>aspectjrt</artifactId>
			<version>1.2</version>
		</dependency>
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjweaver</artifactId>
			<version>1.6.2</version>
			<optional>true</optional>
		</dependency>

         前期工作准备就绪,我们用下面简单的几个代码,让大家看看使用Annotation来配置AOP的方便快捷。
@Aspect
@Component
public class LogInterceptor {
	@Pointcut("execution(public void com.tang.service.*.*(..))")
	public void gogog(){};
	
	@Before("gogog()")
	public void Before(){
		System.out.println("Before execute any of public method");
	}
	
	@Around("gogog()")
	public void Around(ProceedingJoinPoint jp) throws Throwable{
		System.out.println("before around");
		jp.proceed();
		System.out.println("after around");
	}
}

        上面这段代码,就将我com.tang.service这个包下面的所有类的所有public,返回值是void的方法加上了这个日志连拦截器。首先我们看@Aspect标签,表明了这个类就是一个切面类。@Component标签是表示我把这个类也配置进容器来管理。在将AOP的这里意义不大,可以忽略,要提醒大家的是,切面类必须要配置到容器管理,否则是无效的。

        @Pointcut("execution(public void com.tang.service.*.*(..))")这句话其实是定义了一个织入点,准确点说,就是定义了一个切入标准,这个标准内的写法就是"execution(public void com.tang.service.*.*(..))",execution是必须写的关键字,表示这是一个入点语法。public不用解释了,void可以换成其他返回值,或者是*号来表示支持所有返回值的类。空格之后是包名点类名点方法名,这里我只写了包名,类名用*表示该包下面所有类,方法名也用*表示所有方法。后面(..)是表示所支持的传参是所有类型参数。

        我们定义了一个Pointcut后,需要将其发放给一个方法名,public void gogog(){};这句话定义了一个空方法,就是用来接受这个Pointcut的。这时候就能在需要切入的方法上配置了。@Before("gogog()")和@Around("gogog()")都是配置一个advice,这个advice可以表明他是在哪里运行这个类,Before顾名思义是在方法运行前。Around表示了方法执行前后都要插入。还有Afterreturnning表示当正常返回后执行。还有After表示在方法执行完毕后一定会执行, 跟我们写finnally里面执行一样。其他的advice大家可以参考Spring官方的文档,这里就不描述了。
        advice后面括号中的就是我们之前Pointcut定义的那个类,其实这个括号内也可自己写一个织入点语法。如果该切面方法是很特殊的专门用于某个特定方法的切面方法,那么你可以自己再这里定义一个织入点语法。否则建议使用Pointcut来定义织入点,方便其他切面方法复用,详细解释一下上面是如何实现切面的:
//这里使用了gogog()的织入点(gogog()织入点之前的pointcut定义过了)
	@Before("gogog()")
//Before表示方法执行前,该织入点方法执行前,执行下面这个Before方法(方法名可以换)
	public void Before(){
		System.out.println("Before execute any of public method");
	}

//Around很特殊,他所标注的方法需要有个ProceedingJoinPoint参数。而ProceedingJoinPoint.proceed()方法表示我执行原方法,然后我们就能轻松在元方法前后加入自己需要加入的逻辑了。这里前后的逻辑均为打印
	@Around("gogog()")
	public void Around(ProceedingJoinPoint jp) throws Throwable{
		System.out.println("before around");
		jp.proceed();
		System.out.println("after around");
	}

        以上就实现了AOP,我们来看调用代码
	public static void main(String[] args) {
		FileSystemXmlApplicationContext context
			= new FileSystemXmlApplicationContext("/WebRoot/WEB-INF/applicationContext.xml");
		UserService service = (UserService) context.getBean("userService");
		User user = new User();
		service.addUser(user);
		service.deleteUser(user);
	}

         代码中看不出来任何多余的代码,根本不知道是否使用过AOP是吧。其实service的addUser()和deleteUser()方法都是被注解为需要做Before拦截和Around拦截的方法。所以执行这两个方法,势必会执行AOP里面的拦截方法。很给力的注解实现AOP吧。

猜你喜欢

转载自goalietang.iteye.com/blog/2033825
今日推荐