为了账号安全,请及时绑定邮箱和手机立即绑定

【Double Kill】武林秘籍之Spring AOP 切面编程的简单应用

标签:
C

图片描述
年轻人,我观你骨骼精奇,定是万里无一的练武奇才,老夫这里有一本失传已久的武林秘籍,现赠于你,望你勤加苦练,早日修成正果...

AOP(面向切面编程):Aspect Oriented Programming

第一式、使用切面编程需要的配置
<aop:aspectj-autoproxy expose-proxy="true" />

  开启切面编程功能,需要在applicationContext.xml文件中配置。
  作用是:声明自动为spring容器中那些配置@aspectJ切面的bean创建代理,植入切面

第二式、切面编程
  • @Aspect
    放在类头上,把这个类作为一个切面即声明一个切面
  • @Pointcut
    放在方法头上,定义一个可被别的方法引用的切入点表达式。
    Pointcut是Join Point(连接点)的集合,即它是程序中需要注入Advice(切入点上执行的行为)的位置的集合,指明Advice要在什么样的条件下才能被触发。

    • 2.1、Pointcut表达式定义:Pointcut 是指哪些方法需要被执行"AOP",是由"Pointcut Expression"来描述的。 Pointcut可以有下列方式来定义或者通过&& || 和!的方式进行组合。
      args()
      execution()
      this()
      target()
      within()
      annotation
    • 2.2、Pointcut表达式的格式:其中execution 是用的最多的,其格式为:execution(方法操作权限?返回值?方法所在包?方法名(参数)异常?),其中返回值,方法名和参数是必须的。
    • 常用Pointcut表达式的讲解:execution( com.glodon.gcxx.dao.hibimpl..(..)) ,这是com.glodon.gcxx.dao.hibimpl 包下所有的类的所有方法。
      第一个
      代表所有的返回值类型 ,第二个代表所有的类, 第三个代表类所有方法 ,最后一个..代表所有的参数。
      下面给出一些常见切入点表达式的例子。

      1.任意公共方法的执行:execution(public * *(..))
      2.任何一个以“set”开始的方法的执行:execution(* set*(..))
      3.AccountService 接口的任意方法的执行:execution(* com.xyz.service.AccountService.*(..))
      4.定义在service包里的任意方法的执行:execution(* com.xyz.service.*.*(..))
      5.定义在service包或者子包里的任意类的任意方法的执行:execution(* com.xyz.service..*.*(..))
    • Pointcut 可以通过Java注解和XML两种方式配置,如下所示
      <aop:config>
      <aop:aspectrefaop:aspectref="aspectDef">
      <aop:pointcutidaop:pointcutid="pointcut1"expression="execution(* com.test.spring.aop.pointcutexp..JoinPointObjP2.*(..))"/>
      <aop:before pointcut-ref="pointcut1" method="beforeAdvice" />
      </aop:aspect>
      </aop:config>
@Component 
@Aspect 
public class AspectDef { 
    //@Pointcut("execution(* com.test.spring.aop.pointcutexp..JoinPointObjP2.*(..))") 
    //@Pointcut("within(com.test.spring.aop.pointcutexp..*)") 
    //@Pointcut("this(com.test.spring.aop.pointcutexp.Intf)") 
    //@Pointcut("target(com.test.spring.aop.pointcutexp.Intf)") 
    //@Pointcut("@within(org.springframework.transaction.annotation.Transactional)") 
    //@Pointcut("@annotation(org.springframework.transaction.annotation.Transactional)") 
    @Pointcut("args(String)") 
    public void pointcut1() { 
    } 
    @Before(value = "pointcut1()") 
    public void beforeAdvice() { 
        System.out.println("pointcut1 @Before..."); 
    }
  • 3、advice
    5种通知:advice。
    3.1、@Before,前置通知,放在方法头上。
    3.2、@After,后置【finally】通知,放在方法头上。
    3.3、@AfterReturning,后置【try】通知,放在方法头上,使用returning来引用方法返回值。
    3.4、@AfterThrowing,后置【catch】通知,放在方法头上,使用throwing来引用抛出的异常。
    3.5、@Around,环绕通知,放在方法头上,这个方法要决定真实的方法是否执行,而且必须有返回值。
第三式:主要应用场景
  1. 权限控制
  2. 日志
  3. 事务等等
第四式:例子

首先在applicationContext.xml配置中配置:<aop:aspectj-autoproxy expose-proxy="true" />
1、使用execution定义pointcut方式

  • 定义切面
/**
 * 通过aop拦截后执行具体操作
 * @author huangqw
 *  */
@Aspect
@Component
public class LogIntercept {

//  com.glodon.action包下任意公共的(public)方法————解析切入点:public表示操作方法的权限,第一个*表示返回值,com.glodon.action表示报名,..表示子包,第二个*表示类,第三个*表示方法名称,(..)表示参数
    @Pointcut(value="execution(public * com.glodon.action..*.*(..))")
    public void writeLog() {
    }
    <br>//    前置拦截,在执行目标方法之前的操作
    @Before("writeLog()")
    public void before() {
        this.printLog("@Before 方法执行前——————做日志");
    }
//   环绕拦截,在执行目标方法的前后的操作
    @Around("writeLog()")
    public void around(ProceedingJoinPoint pjp) throws Throwable {
        this.printLog("@Around 方法执行前——————做日志");
        pjp.proceed();
        this.printLog("@Around 方法执行后——————做日志");
    }
//      后置拦截,在执行目标方法之前的操作
    @After("writeLog()")
    public void after() {
        this.printLog("@After 方法执行后——————做日志");
    }

    private void printLog(String str) {
        System.out.println(str);
    }
}
  • 使用切面
/**
 * aop测试类
 * @author huangqw
 */
@Controller
public class TestAction {

    public void query() {
        System.out.println("查询操作");
    }

    public static void main(String[] args) {

        @SuppressWarnings("resource")
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("resources/applicationContext.xml");
        TestAction testAction = (TestAction) ctx.getBean("testAction");
        testAction.query();
        ctx.destroy();
    }
}
  • 执行结果
    图片描述
    2、使用注解定义pointcut方式
  • 定义注解:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AroundTest {
    String name() default "测试哈";
}
  • 定义切面
@Component
@Aspect
public class AroundTestInteceptor {
    public AroundTestInteceptor(){
    }

  /**
   * 定义切入点
   */
  @Pointcut(value="@annotation(com.glodon.around.AroundTest)")
    public void logAnnotatedMethod() {
    }

    /**
     * 拦截方法
     * @param pjp
     * @return
     * @throws Throwable
     */
    @Around("logAnnotatedMethod()")
    public Object inteceptorAction(ProceedingJoinPoint pjp) throws Throwable {
        Object o = null;
        MethodSignature joinPointObject = (MethodSignature) pjp.getSignature(); 
        Method method = joinPointObject.getMethod();
        boolean flag = method.isAnnotationPresent(AroundTest.class) ;    
        if (flag) {
               AroundTest annotation = method.getAnnotation(AroundTest.class); 
                Date enterDate = new Date();
                System.out.println("开始执行方法:" + annotation.name());
                  //用于执行委托对象的目标方法
                  o = pjp.proceed();
                  Date leaveDate = new Date();
                  System.out.println("结束执行方法:"+ annotation.name() +",方法执行的时间:" + (leaveDate.getTime() - enterDate.getTime()));
        }
        return o;
    }
}
  • 使用切面
/**
 * aop测试类
 * @author huangqw
 */
@Controller
public class TestAction {

    @AroundTest(name="ceshi")
    public void query() {
        System.out.println("查询操作");
    }

    public static void main(String[] args) {
        @SuppressWarnings("resource")
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("resources/applicationContext.xml");
        TestAction testAction = (TestAction) ctx.getBean("testAction");
        testAction.query();
        ctx.destroy();
    }
}
  • 执行结果
    图片描述
    .
    .
    .
    .
    .
    .
    年轻人,老夫已将所有功力传授与你,望你勤加苦练...阿弥陀佛
    图片描述
点击查看更多内容
7人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
全栈工程师
手记
粉丝
9130
获赞与收藏
5502

关注作者,订阅最新文章

阅读免费教程

感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消