Before 前置处理
在一个切面类里使用@Before来修饰一个方法,该方法将作为Before增强处理。使用@Before修饰时,通常需要指定一个value属性值,该属性指定一个切点表达式(既可以是一个已有的切入点,也可以直接定义切入点表达式),用于指定该增强处理将被织入哪些切入点。
下面定义的java类里使用@Before定义了一个Before增强处理:
// 定义一个切面@Aspectpublic class AuthAspect{// 匹配com.owen.app.service.impl包下所有类的// 所有方法的执行作为切入点@Before("execution(* com.owen.app.service.impl.*.*(..))")public void authority(){System.out.println("模拟执行权限检查");}}
在com.owen.app.service.impl下有两个类分别是HelloImple.java和WorldImpl.java的类。
HelloImple.java
@Component("hello")public class HelloImpl implements Hello{// 定义一个简单方法,模拟应用中的业务逻辑方法public void foo(){System.out.println("执行Hello组件的foo()方法");}// 定义一个addUser()方法,模拟应用中的添加用户的方法public int addUser(String name , String pass){System.out.println("执行Hello组件的addUser添加用户:" + name);return 20;}}
WorldImpl.java
@Component("world")public class WorldImpl implements World{// 定义一个简单方法,模拟应用中的业务逻辑方法public void bar(){System.out.println("执行World组件的bar()方法");}}
从上面的两个类来看,他们都是普通的类,它丝毫不知道将被谁进行增强,也不知道将被进行怎样的增强。下面,在Spring配置文件中配置自动搜索Bean组件、自动搜索切面类,Spring AOP自动对Bean组件进行增强。下面是Spring配置文件代码。(如果后序的AOP中无特殊说明,则用到的文件与这一份相同)
<?xml version="1.0" encoding="GBK"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-4.0.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-4.0.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-4.0.xsd"><!-- 指定自动搜索Bean组件、自动搜索切面类 --><context:component-scan base-package="com.owen.app.service, com.owen.app.aspect"><context:include-filter type="annotation"expression="org.aspectj.lang.annotation.Aspect"/></context:component-scan><!-- 启动@AspectJ支持 --><aop:aspectj-autoproxy/></beans>
下面写一个测试类。
public class BeanTest{public static void main(String[] args){// 创建Spring容器ApplicationContext ctx = newClassPathXmlApplicationContext("beans.xml");Hello hello = ctx.getBean("hello" , Hello.class);hello.foo();hello.addUser("owen" , "7788");World world = ctx.getBean("world" , World.class);world.bar();}}
运行结果如下。
[java]信息:Loading XML bean definitions from class path resource…[java] 模拟执行权限检查[java] 执行Hello组件的foo()方法[java] 模拟执行权限检查[java] 执行Hello组件的addUser添加用户:owen[java] 模拟执行权限检查[java] 执行World组件的bar()方法
总结:
使用Before增强处理只能在目标方法执行之前织入增强,如果Before增强处理没有特殊处理,目标方法总会自动执行,如果Before处需要阻止目标方法的执行,可通过抛出一个异常来实现。Before增强处理执行时,目标方法还未获得执行的机会,所以Before增强处理无法访问目标方法的返回值。
Around 增强处理
@Around 注解用于修饰Around增强处理,Around增强处理是功能比较强大的增强处理,它近似于Before增强处理和AfterReturing增强处理的总结,Around增强处理既可在执行目标方法之前增强动作,也可在执行目标方法之后织入增强的执行。
与Before增强处理、AfterReturning增强处理不同的是,Around增强处理可以决定目标方法在什么时候执行,如何执行,甚至可以完全阻止目标方法的执行。
当定义一个Around增强处理方法时,该方法的第一个形参必须是 ProceedJoinPoint 类型(至少含有一个形参),在增强处理方法体内,调用 ProceedingJoinPoint 参数的 proceed() 方法才会执行目标方法——这就是Around增强处理可以完全控制方法的执行时机、如何执行的关键;如果程序没有调用 ProceedingJoinPoint 参数的 proceed() 方法,则目标方法不会被执行。
Demo Example
服务类:
package com.haan.springdemo.annotation.aop;public class UserService {public String sayHello(String name){System.out.println("UserService.sayHello()执行,"+name + ":hello!");return name;}}
切面类:
package com.haan.springdemo.annotation.aop;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.Signature;import org.aspectj.lang.annotation.*;/*** @Aspect: 告诉Spring当前类是一个切面类*/@Aspectpublic class LogAspect {/*** 抽取公共的切面* 使用:* (1)本类中使用:pointCut()* (2)其他类中使用:com.haan.springdemo.annotation.aop.LogAspect.pointCut()*/@Pointcut(value = "execution(public * com.haan.springdemo.annotation.aop.UserService.*(..))")public void pointCut(){}/*** 前置通知 @Before 在目标方法之前切入* value:切入表达式(指定那个方法切入)*/@Before("pointCut()")public void before(JoinPoint joinPoint){Signature signature = joinPoint.getSignature();String signatureName = signature.getName();System.out.println("测试before...,方法名:"+signatureName);}/*** 后置通知 @After 在目标方法之后切入* value:切入表达式(指定那个方法切入)*/@After("com.haan.springdemo.annotation.aop.LogAspect.pointCut()")public void after(JoinPoint joinPoint){Signature signature = joinPoint.getSignature();String signatureName = signature.getName();System.out.println("测试after...,方法名:"+signatureName);}/*** 返回通知 @AfterReturning* 程序执行无异常,返回结果后切入*/@AfterReturning(value = "pointCut()",returning = "result")public void afterReturning(JoinPoint joinPoint,Object result){Signature signature = joinPoint.getSignature();String signatureName = signature.getName();System.out.println("测试after returning...,方法名:"+signatureName+",return:"+ (String) result);}/*** 异常通知 @AfterThrowing* 程序执行出现异常,切入通知*/@AfterThrowing(value = "pointCut()",throwing = "exception")//JoinPoint一定要出现在参数表的第一位public void afterThrowing(JoinPoint joinPoint,Exception exception){Signature signature = joinPoint.getSignature();String signatureName = signature.getName();System.out.println("测试after throwing...,方法名:"+signatureName);}/*** 环绕通知 @Around**/@Around("pointCut()")public void around(ProceedingJoinPoint pj) throws Throwable {String signatureName = pj.getSignature().getName();System.out.println("测试around...执行前,方法名:"+ signatureName);pj.proceed();System.out.println("测试around...执行后,方法名:"+ signatureName);}}
主程序:
package com.haan.springdemo.annotation.aop;import org.aspectj.lang.annotation.Before;import org.springframework.context.ApplicationContext;import org.springframework.context.ConfigurableApplicationContext;import org.springframework.context.annotation.AnnotationConfigApplicationContext;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.EnableAspectJAutoProxy;@Configuration@EnableAspectJAutoProxypublic class TestAopConfiguration {@Beanpublic LogAspect logAspect(){return new LogAspect();}@Beanpublic UserService userService(){return new UserService();}public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestAopConfiguration.class);UserService userService = context.getBean(UserService.class);userService.sayHello("libai");}}
执行结果:
测试around...执行前,方法名:sayHello测试before...,方法名:sayHelloUserService.sayHello()执行,libai:hello!测试after returning...,方法名:sayHello,return:libai测试after...,方法名:sayHello测试around...执行后,方法名:sayHello
