AOP面向切面编程,它的出现是为了解耦。AOP可以让一组类共享相同的行为。在OOP面向对象编程中只能通过继承和实现接口方式来达到这一目的,但是无论是使用继承还是实现接口都会使代码的耦合度增强。
spring支持AspectJ的注解式切面编程:
-
使用@Aspect声明一个切面。
-
使用@After、@Before、@Around定义建言,可以直接将切点作为参数。
-
使用@PointCut定义切点,使得切点复用。
-
符合条件的被拦截处称为连接点(JoinPoint)
-
作用面
@Service
public class TestAOP{
public int add(int n1,int n2){
int res=n1+n2;
System.out.println(n1+"+"+n2+"="+res);
return res;
}
public int mul(int n1,int n2){
int res=n1*n2;
System.out.println(n1+"*"+n2+"="+res);
return res;
}
}
这个service类是用来承受切面的作用面。
-
切面
@Component
@Aspect
public class Advices {
// 定义切点
@Pointcut("execution(* com.TestAOP.*(..))")
public void pointcut() {
}
// 前置通知
@Before("pointcut()")
public void before(JoinPoint jp) {
// 得到作用于方法上的方法名
System.out.println(jp.getSignature().getName());
System.out.println("----------前置通知----------");
}
// 最终通知
@After("pointcut()")
public void after(JoinPoint jp) {
System.out.println("----------最终通知----------");
}
// 环绕通知
@Around("execution(* com.TestAOP.a*(..))") // 只作用与a开头的方法上
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println(pjp.getSignature().getName());
System.out.println("----------环绕前置----------");
Object result = pjp.proceed();
System.out.println("----------环绕后置----------");
return result;
}
// 返回结果通知
@AfterReturning(pointcut = "pointcut()", returning = "result")
public void afterReturning(JoinPoint jp, Object result) {
System.out.println(jp.getSignature().getName());
System.out.println("结果是:" + result);
System.out.println("----------返回结果----------");
}
// 异常后通知
@AfterThrowing(pointcut = "pointcut()", throwing = "exp")
public void afterThrowing(JoinPoint jp, Exception exp) {
System.out.println(jp.getSignature().getName());
System.out.println("异常消息:" + exp.getMessage());
System.out.println("----------异常通知----------");
}
}
@Pointcut("execution(*com.TestAOP.*(..))")是用于定义一个切点,能够实现复用。
-
xml形式对比
<!-- 通知 -->
<bean id="advices" class="com.TestAOP"></bean>
<!-- aop配置 -->
<aop:config proxy-target-class="true">
<!--切面 -->
<aop:aspect ref="advices">
<!-- 切点 -->
<aop:pointcut expression="execution(* com.TestAOP.*(..))" id="point"/>
<!--连接通知方法与切点 -->
<aop:before method="before" pointcut-ref="point"/>
<aop:after method="after" pointcut-ref="point"/>
</aop:aspect>
</aop:config>
以上的xml形式的代码,就相当于之前使用java代码+注解形式的切面定义和切面方法的编写。
-
配置和运行
@Configuration
@ComponentScan("com.test")
@EnableAspectJAutoProxy
public class Config {
}
@Test
public void run2() {
AnnotationConfigApplicationContext cc = new AnnotationConfigApplicationContext(Config.class);
Math math = cc.getBean(Math.class);
math.add(10, 20);
math.mul(1, 2);
}
注:使用@EnableAspectJAutoProxy注解开启spring对AspectJ代理的支持