在学习课程以前,听说AOP有种很神秘的感觉,好像很好深的技术。其实原理很简单,使用动态代理的方式给程序增加逻辑。与此相似的有struts2中的filter拦截器。
再讲AOP之前先把需求说一下: 同Spring学习笔记(一)IoC中的需求一样,只不过要在save()方法前后增加日志log的记录。
不使用AOP的方式可以有两种实现思路:
1—>使用继承的的方式,把有save方法的类继承,然后在增加log逻辑
2—>使用组合的方式,即增加一个记录逻辑的类,分别有在save()方法前save()方法后记录日志的功能,然后把这两个类组合到一起
虽然上面两种方式都能解决我们的需求,但是一个问题来了:如果有500个更甚至1000各类中的方法需要增加逻辑,使用继承的方法和组合的方法的弊端就出来了。一方面会增加海量的代码量。另一方面,会使整个程序的可读性变差。程序员在写程序的时候不能专注于业务逻辑,还要专注于维护逻辑,增加程序员的逻辑压力,从而用于调试的时间会增多。
从而,出现了AOP,来解决这类问题。Spring中的AOP实现原理使用的是JavaJDK中的动态代理。
AOP_annotation
AOP_annotation环境搭建
-
<?xml version="1.0" encoding="UTF-8"?>
-
<beans xmlns="http://www.springframework.org/schema/beans"
-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-
xmlns:aop="http://www.springframework.org/schema/aop"
-
xsi:schemaLocation="http://www.springframework.org/schema/beans
-
http://www.springframework.org/schema/aop
-
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
-
<aop:aspectj-autoproxy />
-
</beans>
增加AOP的xml命名空间以及xsd路径设置。最重要的是增加<aop:aspect-autoproxy>
Aspectj是专门用来实现动态代理的类库,spring中的AOP使用的是aspectj.jar实现的。需要在库中增加aspectj的类库。
@Aspect,@Before
@Aspect:即标注这个类为切面类,是增加的逻辑的那个类。放在我们的需求里面,log记录方法应写在被@Aspect标注的类
@Before:切入点的逻辑,即是在增加save()方法前面执行
Execution…:切入点语法
-
@Aspect
-
@Component
-
public class LogInterceptor {
-
@Before("execution(* com.xxxx.dao.impl.UserDAOImpl.save(com.xxxx.model.User))")
-
public void before() {
-
System.out.println("method before");
-
}
-
}
其中@Before口号中的execution()是注册那个保重的那个类中的那个方法加入切入逻辑。
@PointCut
-
@Aspect
-
@Component
-
public class LogInterceptor {
-
@Pointcut("execution(public * com.xxxx.service..*.add(..))")
-
public void myMethod(){};
-
}
@PointCut:切入点集合。即对com.xxx.service包中的类中任何返回值的add()方法(add()方法的参数任意)增加切入逻辑
这种给相关方法加入切入逻辑的动作又叫作织入(Weave),切入点语法为execution的为aspectj的织入语法。Spring AOP也有自己的语法,到时候查阅参考文档吧!
@AfterReturning,@AfterThrowing,@After(finally)
这些方法的使用跟@Before类似
@Around
-
@Aspect
-
@Component
-
public class LogInterceptor {
-
@Pointcut("execution(public * com.bjsxt.service..*.add(..))")
-
public void myMethod(){};
-
@Around("myMethod()")
-
public void aroundMethod(ProceedingJoinPoint pjp) throws Throwable {
-
System.out.println("method around start");
-
pjp.proceed();
-
System.out.println("method around end");
-
}
-
}
其中有两个知识点
1à这一点在刚才说@PointCut是没有说明,就是呗@PointCut标记的方法名字myMethod为@PointCut所标记的那些切入点方法集合的表示符号。举个例子,
int myMethod=@PointCut
2à@around要使用pjp.proceed()执行切入点save()方法
AOP_XML
-
<bean id="logInterceptor" class="com.bjsxt.aop.LogInterceptor" ></bean>
-
<aop:config>
-
<aop:aspect id="logAspect" ref="logInterceptor" >
-
<aop:pointcut id="myMethod" expression="execution(public void com.bjsxt.dao.impl.UserDAOImpl.save(com.bjsxt.model.User))"></aop:pointcut>
-
<aop:before method="before" pointcut-ref="myMethod"></aop:before>
-
<aop:after-returning method="myafter" pointcut="execution(public void com.bjsxt.dao.impl.UserDAOImpl.save(com.bjsxt.model.User))">
-
</aop:aspect>
-
</aop:config>
上述代码写了AOP中XML方式书写的格式,其中pointcut的三种写法都在上面4,5,6行中。