• 【Spring】AOP相关、五种增强方式、IoC与AOP注解开发、纯注解开发


    AOP(面向切面编程

    一、什么是AOP

    【=====AOP即 Aspect Oriented Program 面向切面编程(公共功能集中解决),目的是为了让我们专心的做业务 。不改变源码的基础上新增功能,是Spring最为重要的功能之一 =====】

    在这里插入图片描述
    AOP相关术语:

    • 增强处理(Advice)----五种增强方式
    • 切入点(Pointcut):在哪些类,哪些方法上切入(where)
    • 连接点(Join Point):连接点=通知,在方法执行的什么实际(when:方法前/方法后/方法前后)做什么(what:增强的功能)
    • 切面(Aspect):切面 = 切入点 + 通知,通俗点就是:在什么时机,什么地方,做什么增强。
    • 目标对象(Target object):业务
    • AOP代理(AOP proxy):代理类,xml文件
    • 织入(Weaving):把切面加入到对象,并创建出代理对象的过程。(由 Spring 来完成)
      在这里插入图片描述

    二、五种增强方式

    1.简介
    目录说明使用
    前置增强在目标方法前织入增强处理before
    后置增强在目标方法之后正常执行,执行通知,若是报错,不执行after-returning
    最终增强在目标方法执行之后,只有在方法成功完成时,才能执行通知。after
    异常增强在一个方法执行之后,只有在方法退出抛出异常时,才能执行通知after-throwing
    环绕增强在一个方法执行之前,执行通知around

    【当目标方法出错时,后置增强不执行,最终增强会执行;有异常执行异常增强,不报错执行后置增强】

    2.代码步骤

    【五种增强的整个demo代码下面已给,需要自取,接口和方法随意建吧】

    • 第一步:导包
    //pom.xml
    
    	<dependency>
          <groupId>org.aspectjgroupId>
          <artifactId>aspectjweaverartifactId>
          <version>1.9.5version>
        dependency>
    
        <dependency>
          <groupId>log4jgroupId>
          <artifactId>log4jartifactId>
          <version>1.2.17version>
        dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 第二步:创建目标方法
    //dao、service接口
    public interface UserDao {
        public int addNewUser(User user);
    }
    
    //dao实现
    public class UserDaoImpl implements UserDao {
        public int addNewUser(User user) {
            System.out.println("新添加一个对象~~~");
            return 0;
        }
    }
    
    //service实现
    @Setter
    public class UserServiceImpl implements UserService {
        private UserDao userDao;   
        public int addNewUser(User user) {
            return userDao.addNewUser(user);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 第三步:创建增强类【根据自己建立的包单独创建一个aop包,我的目录“com.jules.aop.UserLogge”,在配置文件是要创建bean的】
    /**
     * 增强类
     */
    public class UserLogger {
        private static final Logger log = Logger.getLogger(UserServiceLogger.class);
        //前置增强
        public void beforeLogger(JoinPoint jp) {
            System.out.print("我是前置增强…………");
            System.out.println("调用 " + jp.getTarget() + " 的 " + jp.getSignature().
                    getName() + " 方法。方法入参:" + Arrays.toString(jp.getArgs()));
        }
        //后置增强
        public void afterReturning(JoinPoint jp, Object result) {
            System.out.print("我是后置增强…………");
            log.info("调用 " + jp.getTarget() + " 的 " +  jp.getSignature().
                    getName() + " 方法。方法返回值:" + result);
        }
    
        //最终增强
        public void afterLogger(JoinPoint jp) {
            System.out.print("我是最终增强…………");
            log.info("最终增强:"+jp.getSignature().getName()+"方法结束执行。");
        }
    
        //异常增强
        public void afterThrowing(JoinPoint jp,RuntimeException e){
            log.error("异常抛出:"+jp.getSignature().getName()+"方法发生异常:"+e);
    
        }
    
        //环绕增强,需要调用目标方法
        public Object aroundLogger(ProceedingJoinPoint jp) throws Throwable{
            System.out.println("环绕增强开始…………");
            log.info("环绕增强:调用"+jp.getTarget()+"的"+jp.getSignature().getName()+"方法,方法入参:"+Arrays.toString(jp.getArgs()));
            try{
                Object result = jp.proceed(); //调用目标方法
                log.info("环绕增强:调用"+jp.getTarget()+"的"+jp.getSignature().getName()+"方法。方法返回值:"+result);
                return result;
            }catch(Throwable e){
                log.error("环绕增强:"+jp.getSignature().getName()+"方法发生异常:"+e);
                throw e;
            }finally{
                log.info("环绕增强:"+jp.getSignature().getName()+"方法结束执行。");
                System.out.println("环绕增强结束~~~");
            }
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 第四步:配置文件
    //添加关于aop的头部文件:
    xmlns:aop="http://www.springframework.org/schema/aop"
    
    http://www.springframework.org/schema/aop 
    http://www.springframework.org/schema/aop/spring-aop.xsd
    
      
      <bean id="serviceLogger" class="com.jules.aop.UserLogger"/>
      
      
      <aop:config>
          
          <aop:pointcut id="pointcut" expression="execution(* com.jules.service.*.*.*(..))">aop:pointcut>
          
          <aop:aspect ref="serviceLogger">
              
              <aop:before method="beforeLogger" pointcut-ref="pointcut"/>
              
              <aop:after-returning method="afterReturning" pointcut-ref="pointcut" returning="result"/>
              
              <aop:after method="afterLogger" pointcut-ref="pointcut"/>
              
              <aop:after-throwing method="afterThrowing" pointcut-ref="pointcut" throwing="e"/>
              
              <aop:around method="aroundLogger" pointcut-ref="pointcut"/>
          aop:aspect>
      aop:config>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 第五步:测试类
    public class Test {
        @Test
        public void addNewUser() {
                //使用ClassPathXmlApplicationContext读取配置文件
                ApplicationContext context = new ClassPathXmlApplicationContext("配置文件名");
                //使用getBean("bean中ID属性值")获取对象
                UserService userService = (UserService) context.getBean("userService");
                userService.addNewUser(new User()); //添加空对象测试异常增强
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    3.spring AOP配置元素
    目录说明
    aop:configAOP配置
    aop:pointcut定义切点
    aop:aspect定义切面
    aop:before定义前置增强
    aop:after-returning定义后置增强
    aop:after定义最终增强
    aop:after-throwing定义异常增强
    aop:around定义环绕增强
    aop:aspectj-autoproxy/启动@AspectJ注解驱动的切面
    4.execution表达式匹配规则:
    <aop:pointcut id="pointcut" expression="execution(* com.jules.service.*.*.*(..))">aop:pointcut>
    
    public * addNewUser(entity.User)----- “ * ”表示匹配所有类型的返回值。
    public void *(entity.User)------“ * ”表示匹配所有方法名。
    public void addNewUser(..)-------“..”表示匹配所有参数个数和类型。
    * com.service.*.*(..)-------匹配com.service包下所有类的所有方法。
    * com.service..*.*(..)-------匹配com.service包及其子包下所有类的所有方法
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    三、IOC注解开发

    使用注解开发,则配置文件中创建的bean就可以被代替掉

    
     <bean id="userDao" class="com.hz.dao.impl.UserDaoImpl">bean>
     <bean id="userService" class="com.hz.service.impl.UserServiceImpl"/>                
    
    • 1
    • 2
    • 3

    【其他类用@Component,虽然哪里都可以使用但为了辨识,出现了下面的注解
    Dao实现用@Repository,service用@Service,控制类用@Controller】

    • 使用注解将bean的定义信息和bean实现类结合在一起,spring提供的注解有
      • @Component:实现Bean组件的定义( 在dao类和service类也可以使用的,但一般用来标注其他类,用于明显区别 )
      • @Repository:用于标注DAO类
      • @Service:用于标注业务类
      • @Controller:用于标注控制器类
      • @Autowired+@Qualifier(“userDao”)等价于@Resource(name = “userDao”)
    • 示例:
      • 第一步:使用注解前要先开启注解:添加context的命名空间

        	
        	<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:p="http://www.springframework.org/schema/p"
        	       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/context http://www.springframework.org/schema/context/spring-context.xsd
        	            ttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
        	        ">
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
      • 第二步:添加扫描,标注要是用注解的类

        
         <context:component-scan base-package="com.jules,service,com,jules.dao" />
        
        • 1
        • 2
      • 第三步:使用示例

        @Component   //直接使用相当于有一个别名"userDaoImpl"
        @Component("userDao")   //自己命名,等效
        @Repository("userDao")   //与@Component的使用没区别
        public class UserDaoImpl implements UserDao{
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5

        在这里插入图片描述

        	@Resource  是java下的包,import javax.annotation.Resource;
        	@Autowired 实际是按数据类型进行注入的。是spring下的包,import org.springframework.beans.factory.annotation.Autowired;
        		它是根据UserDao 类型注入的------
        		倘若有private UserDao userDao11;private UserDao userDao22;它是无法识别的,要与@Qualifier("")搭配使用变为按名字进行注入。
        	@Autowired+@Qualifier("userDao")=====@Resource(name = "userDao")	
        
        
        //@Setter
        @Service("userService)
        public class UserServiceImpl implements UserService {
        	//在service层中要引用dao层,bean的关系绑定
        	@Resource 
        	@Autowired   
            private UserDao userDao;
            
            public int addNewUser(User user) {
                user.setUserName(uname);
                user.setUserCode(ucode);
                return userDao.addNewUser(user);
            }
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21

        在这里插入图片描述

    四、AOP注解开发

    1.使用注解定义切面
    • AapectJ:面向切面的框架,它扩展了Java语言,定义了AOP语法,能够在编译器提供代码的织入
    • @AspectJ:AspectJ 5 新增的功能,使用JDK5.0注解技术和正规的AspectJ切点表达式语言描述切面
    • Spring通过集成AspectJ实现了以注解的方式定义增强类,大大减少了配置文件中的工作量,利用轻量级的字节码处理框架asm处理@AspectJ中所描述的方法参数名
    • 使用@AspectJ,首先要保证所用的JDK是5.0或以上版本。
    • 常用注解:
      • @Aspect
      • @Before
      • @AfterReturning
      • @Around
      • @AfterThrowing
      • @After
    • 在配置文件中添加启动@AspectJ注解的支持
    2.增强的注解代码示例:

    之前在介绍五种增强的时候,spring配置文件中的实例化增强类bean和定义切面的配置就不需要,只需要扫描包和开启AOP注解就可。

        
        <context:component-scan base-package="com.jules.aop"/>
        
        <aop:aspectj-autoproxy/>
    
    • 1
    • 2
    • 3
    • 4
    **/**
     * 使用注解定义切面
     */
    @Component
    @Aspect
    public class UserServiceLogger {
        private static final Logger log = Logger.getLogger(UserServiceLogger.class);
    
        @Pointcut("execution(* com.hz.service.*.*(..))")
        public void pointcut() {
        }
    
        //前置增强
        @Before("pointcut()")
        public void beforeLogger(JoinPoint jp) {
            System.out.print("我是前置增强…………");
            System.out.println("调用 " + jp.getTarget() + " 的 " + jp.getSignature().
                    getName() + " 方法。方法入参:" + Arrays.toString(jp.getArgs()));
        }
        //后置增强
        @AfterReturning(pointcut = "pointcut()", returning = "result")
        public void afterReturning(JoinPoint jp, Object result) {
            System.out.print("我是后置增强…………");
            log.info("调用 " + jp.getTarget() + " 的 " +  jp.getSignature().
                    getName() + " 方法。方法返回值:" + result);
        }
    
        //最终增强
        @After("pointcut()")
        public void afterLogger(JoinPoint jp) {
            System.out.println("我是最终增强…………");
            log.info("最终增强:"+jp.getSignature().getName()+"方法结束执行。");
        }
    
        //异常增强
        @AfterThrowing(pointcut = "pointcut()", throwing = "e")
        public void afterThrowing(JoinPoint jp,RuntimeException e){
            log.error("异常抛出:"+jp.getSignature().getName()+"方法发生异常:"+e);
        }
    
        //环绕增强,需要调用目标方法
        @Around("pointcut()")
        public Object aroundLogger(ProceedingJoinPoint jp) throws Throwable{
            System.out.println("环绕增强开始==========");
            log.info("环绕增强:调用"+jp.getTarget()+"的"+jp.getSignature().getName()+"方法,方法入参:"+Arrays.toString(jp.getArgs()));
            try{
                Object result = jp.proceed(); //调用目标方法
                log.info("环绕增强:调用"+jp.getTarget()+"的"+jp.getSignature().getName()+"方法。方法返回值:"+result);
                return result;
            }catch(Throwable e){
                log.error("环绕增强:"+jp.getSignature().getName()+"方法发生异常:"+e);
                throw e;
            }finally{
                log.info("环绕增强:"+jp.getSignature().getName()+"方法结束执行。");
                System.out.println("环绕增强结束=============");
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    在这里插入图片描述




    *纯注解开发(了解)

    在这里插入图片描述

    • 容器的对象的获取使用AnnotationConfigApplicationContext
      在这里插入图片描述

      1. bean作用范围:@Scope
      1. bean生命周期:@PostConstruct、@PreDestroy
        在这里插入图片描述
        在这里插入图片描述
    • 依赖注入:@Autowired注入引用类型(上面讲解过),@Value注入普通类型
      在这里插入图片描述

    • 加载properties的配置文件:
      在这里插入图片描述

    • 注解开发管理第三方Bean,没有配置文件
      在这里插入图片描述
      倘若此类中还要加载其他东西,太混乱了,要把他们分开进入不同类中,在SpringConfig中加载
      方式一:

    在这里插入图片描述
    方式二:不推荐,麻烦
    在这里插入图片描述

    • 注解开发实现为第三方Bean注入资源
      在这里插入图片描述

    在这里插入图片描述

  • 相关阅读:
    梳理一下我所知的输入输出流
    实现风控中台案例分析
    概率公式c的计算
    Spring注解大全,最后一个经常容易记不住
    springboot生成二维码的正确姿势-附视频附源码
    队列题目:按递增顺序显示卡牌
    java-php-python-中小型超市管理系统计算机毕业设计
    android绘制心电图
    大数据中的分布式文件系统MapReduce的选择题
    Python教程之使用 Python 识别加密的 PDF 文档和解密受 PDF
  • 原文地址:https://blog.csdn.net/m0_70083523/article/details/127651515