• spring Aop 注解


    个人理解:

    spring Aop 是什么:面向切面编程,类似于自定义拦截操作,支持拦截之前操作@Before,拦截之后操作@After,拦截环绕操作@Around。

    什么情况下使用spring Aop:举例如下

    1. 当需要统计某些方法 or 指定xx开头的方法名 or 指定xx结尾的方法名 or 某些类下的方法 or 某些包下的方法 or 所有的方法的耗时统计或添加日志信息时,使用spring Aop 切面编程可以不用修改任何需要统计或添加日志的方法,只需很少一部分代码实现需要做的操作。
    2. 某交易系统需要限制每个登陆用户查询次数时,spring Aop 切面编程在不修改原有代码上可以完美实现。

    code案例:

    applicationContext.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:context="http://www.springframework.org/schema/context"
    	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:p="http://www.springframework.org/schema/p"
    	xmlns:task="http://www.springframework.org/schema/task"
    	xsi:schemaLocation="http://www.springframework.org/schema/beans   
               http://www.springframework.org/schema/beans/spring-beans-4.1.xsd   
               http://www.springframework.org/schema/context   
               http://www.springframework.org/schema/context/spring-context-4.1.xsd
               http://www.springframework.org/schema/aop 
               http://www.springframework.org/schema/aop/spring-aop-4.1.xsd   
               http://www.springframework.org/schema/task
               http://www.springframework.org/schema/task/spring-task-4.1.xsd ">
    	
    	<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
             <property name="locations">
                 <value>classpath:propertiesConfig/test.properties</value>
             </property>
        </bean>
    	
    	<!-- 扫描@Controller注解 -->
    	<context:component-scan base-package="com.maven.project">
    		<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
    	</context:component-scan>
    	
    	<!-- 开启AOP监听 只对当前配置文件有效 -->
    	<aop:aspectj-autoproxy expose-proxy="true"></aop:aspectj-autoproxy>
    	
    	<task:executor id="executor" pool-size="5" />
    	<task:scheduler id="scheduler" pool-size="10" />
    	<task:annotation-driven executor="executor" scheduler="scheduler" />
    	
    	<!-- 线程池 -->
    	<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">   
    		<!-- 线程池维护线程的最少数量 -->
    	    <property name="corePoolSize" value="10" />   
    	     <!-- 线程池维护线程所允许的空闲时间 -->
    	    <property name ="keepAliveSeconds" value ="300" /> 
    	    <!-- 线程池维护线程的最大数量 -->
    	    <property name="maxPoolSize" value="100" />   
    	    <!-- 线程池所使用的缓冲队列 -->
    	    <property name="queueCapacity" value="25" /> 
    	</bean>
    	
    	<bean id="viewResolver"
    		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    		<property name="viewClass">
    			<value>org.springframework.web.servlet.view.JstlView</value>
    		</property>
    		<property name="prefix">
    			<value>/</value>
    		</property>
    		<property name="suffix">
    			<value>.jsp</value>
    		</property>
    	</bean>
    
    </beans>
    

      

    maven pom.xml  spring Aop dependency

    <!-- Spring AOP + AspectJ  -->
    	        <dependency>
    	            <groupId>org.springframework</groupId>
    	            <artifactId>spring-aop</artifactId>
    	            <version>${spring.version}</version>
    	        </dependency>
    	        <dependency>
    	            <groupId>org.springframework</groupId>
    	            <artifactId>spring-aspects</artifactId>
    	            <version>${spring.version}</version>
    	        </dependency>
    	        <dependency>
    	            <groupId>org.aspectj</groupId>
    	            <artifactId>aspectjrt</artifactId>
    	            <version>1.6.11</version>
    	        </dependency>
    	        <dependency>
    	            <groupId>org.aspectj</groupId>
    	            <artifactId>aspectjweaver</artifactId>
    	            <version>1.6.12</version>
    	        </dependency>
    	        <dependency>
    	            <groupId>cglib</groupId>
    	            <artifactId>cglib</artifactId>
    	            <version>2.2</version>
    	        </dependency>
            <!-- end -->
    

      

    spring Aop 切面业务处理类

    package com.maven.project.web.aop;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    import org.springframework.stereotype.Component;
    
    @Component
    @Aspect
    public class CustomAspect {
        
        //com.maven.project.services包下(包括子包下 的)for开头的方法
        @Pointcut("execution(* com.maven.project.services..for*(..))")
        public void query(){}
        
        //所有使用@QuerySystem自定义注解的方法 
        @Pointcut("@annotation(com.maven.project.web.customAnnotations.QuerySystem)")
        public void loginTimeOut(){}
        
        
        @Before("query()")//方法之前执行
        public void queryBefore(JoinPoint joinPoint){
            System.out.println("=======query start @Before ====方法名称:"+joinPoint.getSignature().getName());
        }
        
        @After("query()")//方法之后执行
        public void queryAfter(JoinPoint joinPoint){
            System.out.println("=======query end @After ====方法名称:"+joinPoint.getSignature().getName());
        }
        
        @Around("query()")//方法前后执行,如果需要返回值,则必须  return joinPoint.proceed(); 返回类型为Object
        public void queryAround(ProceedingJoinPoint joinPoint) throws Throwable{
            System.out.println("=======query start @Around ====方法名称:"+joinPoint.getSignature().getName());
            joinPoint.proceed();
            System.out.println("=======query end @Around ====方法名称:"+joinPoint.getSignature().getName());
        }
        
        @Around("loginTimeOut()")
        public void times(ProceedingJoinPoint joinPoint) throws Throwable{
            long start = System.currentTimeMillis();
            joinPoint.proceed();
            long end = System.currentTimeMillis();
            System.out.println("======= 登陆耗时:"+(end-start)/1000+" ====方法名称:"+joinPoint.getSignature().getName());
        }
    }

    自定义注解

    package com.maven.project.web.customAnnotations;
    import java.lang.annotation.*;
    
    @Target({ElementType.PARAMETER, ElementType.METHOD})  
    @Retention(RetentionPolicy.RUNTIME)  
    @Documented  
    public @interface QuerySystem {
        String description() default "";
    }

     

    引用自定义注解的方法

        @RequestMapping("/login")
        @QuerySystem //自定义注解引用
        public void login(HttpServletRequest request, HttpServletResponse response) {
          // 方法实现,,,,
        }

    execution 表达式
    1、execution(): 表达式主体。
     2、第一个*号:表示返回类型,*号表示所有的类型。
     3、包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,com.sample.service.impl包、子孙包下所有类的方法。
     4、第二个*号:表示类名,*号表示所有的类。
     5、*(..):最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数。
     
    AspectJ的Execution表达式
    execution()是最常用的切点函数,其语法如下所示:
     
    execution(<修饰符模式>? <返回类型模式> <方法名模式>(<参数模式>) <异常模式>?)  除了返回类型模式、方法名模式和参数模式外,其它项都是可选的。与其直接讲解该方法的使用规则,还不如通过一个个具体的例子进行理解。下面,我们给出各种使用execution()函数实例。
     
    1)通过方法签名定义切点
     execution(public * *(..))l
    匹配所有目标类的public方法,但不匹配SmartSeller和protected void showGoods()方法。第一个*代表返回类型,第二个*代表方法名,而..代表任意入参的方法;
     
     execution(* *To(..))l
    匹配目标类所有以To为后缀的方法。它匹配NaiveWaiter和NaughtyWaiter的greetTo()和serveTo()方法。第一个*代表返回类型,而*To代表任意以To为后缀的方法;
     
    2)通过类定义切点
     execution(* com.baobaotao.Waiter.*(..))l
    匹配Waiter接口的所有方法,它匹配NaiveWaiter和NaughtyWaiter类的greetTo()和serveTo()方法。第一个*代表返回任意类型,com.baobaotao.Waiter.*代表Waiter接口中的所有方法;
     
     execution(* com.baobaotao.Waiter+.*(..))l
    匹 配Waiter接口及其所有实现类的方法,它不但匹配NaiveWaiter和NaughtyWaiter类的greetTo()和serveTo()这 两个Waiter接口定义的方法,同时还匹配NaiveWaiter#smile()和NaughtyWaiter#joke()这两个不在Waiter 接口中定义的方法。
     
    3)通过类包定义切点
    在类名模式串中,“.*”表示包下的所有类,而“..*”表示包、子孙包下的所有类。
     execution(* com.baobaotao.*(..))l
    匹配com.baobaotao包下所有类的所有方法;
     
     execution(* com.baobaotao..*(..))l
    匹 配com.baobaotao包、子孙包下所有类的所有方法,如com.baobaotao.dao,com.baobaotao.servier以及 com.baobaotao.dao.user包下的所有类的所有方法都匹配。“..”出现在类名中时,后面必须跟“*”,表示包、子孙包下的所有类;
     
     execution(* com..*.*Dao.find*(..))l
    匹配包名前缀为com的任何包下类名后缀为Dao的方法,方法名必须以find为前缀。如com.baobaotao.UserDao#findByUserId()、com.baobaotao.dao.ForumDao#findById()的方法都匹配切点。
     
    4)通过方法入参定义切点
    切点表达式中方法入参部分比较复杂,可以使用“*”和“ ..”通配符,其中“*”表示任意类型的参数,而“..”表示任意类型参数且参数个数不限。
     
     execution(* joke(String,int)))l
    匹 配joke(String,int)方法,且joke()方法的第一个入参是String,第二个入参是int。它匹配 NaughtyWaiter#joke(String,int)方法。如果方法中的入参类型是java.lang包下的类,可以直接使用类名,否则必须使用全限定类名,如joke(java.util.List,int);
     
     execution(* joke(String,*)))l
    匹 配目标类中的joke()方法,该方法第一个入参为String,第二个入参可以是任意类型,如joke(String s1,String s2)和joke(String s1,double d2)都匹配,但joke(String s1,double d2,String s3)则不匹配;
     
     execution(* joke(String,..)))l
    匹配目标类中的joke()方法,该方法第 一个入参为String,后面可以有任意个入参且入参类型不限,如joke(String s1)、joke(String s1,String s2)和joke(String s1,double d2,String s3)都匹配。
     
     execution(* joke(Object+)))l
    匹 配目标类中的joke()方法,方法拥有一个入参,且入参是Object类型或该类的子类。它匹配joke(String s1)和joke(Client c)。如果我们定义的切点是execution(* joke(Object)),则只匹配joke(Object object)而不匹配joke(String cc)或joke(Client c)。
     
    

      

     
  • 相关阅读:
    HTML连载29-div和span标签
    Java连载14-补码简介&浮点型整数
    Java连载13-整数型字面值的强制转换
    Java连载12-继承开发环境&long类型
    [Python] tkinter 之 Listbox & Combobox
    [Python] Tkinter command
    [java] 转型
    [Python] execl读写
    [c++] 细节
    [刷题] PTA 7-64 最长对称子串
  • 原文地址:https://www.cnblogs.com/jianqiao/p/6068559.html
Copyright © 2020-2023  润新知