• 【一步一步学习spring】spring 基于AspectJ的注解AOP开发


    1. AspectJ的简介

    • AspectJ是一个基于java语言的AOP框架
    • spring 2.0以后新增了对AspectJ切点表达式的支持
    • @AspectJ,允许直接在Bean类中定义切面
    • 新版本的spring框架,建议使用AspectJ方式来开发AOP

    2. 环境准备

    • 引入xml中aop约束
    <?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/beans/spring-beans.xsd
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    </beans>
    
    • 引入aop AspectJ相关的依赖
    <dependency>
        <groupId>aopalliance</groupId>
        <artifactId>aopalliance</artifactId>
        <version>1.0</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>4.3.18.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.8.9</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>4.3.18.RELEASE</version>
    </dependency>
    

    3. AspectJ 通知类型列举

    • @Before 前置通知
    • @AfterReturning 后置通知
    • @Around 环绕通知,最强大的,可以阻止方法执行
    • @AfterThrowing 异常抛出通知
    • @After 最终通知,无论是否有异常

    4. excution函数语法

    • 通过excution函数,可以定义切点的方法切入
    • 语法:
      • execution(<访问修饰符>?<返回类型><方法名>(<参数>)<异常>)
    • 例如:
      • 匹配所有类public方法 execution(public * * ())
      • 匹配指定包下所有类方法 execution(* com.aop.dao.*(..)) 不包含子包中的类
      • execution(* com.aop.dao..*(..)) 包、子孙包下的所有类
      • 匹配指定类所有方法 execution(* com.aop.dao.UserDao.*(..))
      • 匹配实现特定接口所有类的方法 execution(* com.aop.dao.IDao+.*(..))
      • 匹配所有save开头的方法 execution(* save*(..))

    5. 栗子

    • 目标类
    package com.aop.aspectj;
    
    public class ProductDao {
    	public void save(){
    		System.out.println("save");
    	}
    	public void update(){
    		System.out.println("update");
    	}
    	public void delete(){
    		System.out.println("delete");
    	}
    	public void findone(){
    		System.out.println("findone");
    	}
    	public void findall(){
    		System.out.println("findall");
    		int i = 1 / 0;
    	}
    }
    
    • 切面类
    package com.aop.aspectj;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.AfterReturning;
    import org.aspectj.lang.annotation.AfterThrowing;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    
    @Aspect
    public class MyAspect {
    
    	@Before(value = "execution(* com.aop.aspectj.ProductDao.save(..))")
    	public void before(JoinPoint point) {
    		System.out.println("==========before========" + point);
    	}
    
    	@AfterReturning(value = "execution(* com.aop.aspectj.ProductDao.delete(..))", returning="result")
    	public void afterReturning(Object result) {
    		System.out.println("===========after returning========" + result);
    	}
    
    	@After(value = "execution(* com.aop.aspectj.ProductDao.findone(..))")
    	public void after() {
    		System.out.println("=========after==============");
    	}
    
    	@Around(value = "execution(* com.aop.aspectj.ProductDao.update(..))")
    	public Object around(ProceedingJoinPoint point) throws Throwable {
    		System.out.println("===========around start===========");
    		Object o = point.proceed();
    		System.out.println("==========around end========");
    		return o;
    	}
    
    	@AfterThrowing(value="execution(* com.aop.aspectj.ProductDao.findall(..))", throwing="e")
    	public void afterThrowable(Throwable e) {
    		System.out.println("===========throw============" + e);
    	}
    }
    
    
    • xml
    <?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/beans/spring-beans.xsd
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    	
    	<!-- 开启aspectj自动代理 -->
    	<aop:aspectj-autoproxy/>
    	
    	<bean id="productDao" class="com.aop.aspectj.ProductDao"/>
    	<bean class="com.aop.aspectj.MyAspect"/>
    </beans>
    
    • 调用
    package com.aop.aspectj;
    
    import javax.annotation.Resource;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:application-context-aop-aspectj.xml")
    public class SpringDemo {
    
    	@Resource(name="productDao")
    	private ProductDao dao;
    	
    	@Test
    	public void demo1() {
    		dao.save();
    		dao.delete();
    		dao.update();
    		dao.findall();
    		dao.findone();
    	}
    }
    

    6. 通过@Pointcut 为切点命名

    • 在每个通知内定义切点,会造成工作量大,不易维护,对于重复的切点,可以使用@Pointcut进行定义
    • 切点方法:private void 无参数方法,方法名为切点名
    • 当通知有多个切点,可以使用||进行连接
    @Around(value = "pointcut1()||pointcut2()||pointcut3()||pointcut4()||pointcut5()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        System.out.println("===========around start===========");
        Object o = point.proceed();
        System.out.println("==========around end========");
        return o;
    }
    
    @Pointcut(value = "execution(* com.aop.aspectj.ProductDao.save(..))")
    private void pointcut1() {
    }
    
    @Pointcut(value = "execution(* com.aop.aspectj.ProductDao.delete(..))")
    private void pointcut2() {
    }
    
    @Pointcut(value = "execution(* com.aop.aspectj.ProductDao.findone(..))")
    private void pointcut3() {
    }
    
    @Pointcut(value = "execution(* com.aop.aspectj.ProductDao.update(..))")
    private void pointcut4() {
    }
    
    @Pointcut(value = "execution(* com.aop.aspectj.ProductDao.findall(..))")
    private void pointcut5() {
    }
    
  • 相关阅读:
    [NOIp pj 2007][Luogu P1095] 守望者的逃离
    [Noip 2009 普及组 T4] [Luogu P1070] 道路游戏
    跟风Manacher算法整理
    Luogu P2569 [SCOI2010] 股票交易
    qbzt2020五一DAY1T1集合——题解
    Cena使用教程
    2020.4.15校内测试
    康托展开学习笔记
    qbzt网格图路径问题——题解
    2-sat基础详解
  • 原文地址:https://www.cnblogs.com/xxxuwentao/p/9600489.html
Copyright © 2020-2023  润新知