zoukankan      html  css  js  c++  java
  • Spring技术内幕总结

    AOP是Aspect-Oriented Programming(面向方面/切面编程)的简称。Aspect是一种新的模块化机制,用来描述分散在对象、类或函数中的横切关注点。分离关注点使解决特定领域问题的代码从业务逻辑中独立出来,业务逻辑的代码中不再含有针对特定领域问题代码的调用,业务逻辑同特定领域问题的关系通过切面来封装、维护,这样原来分散在整个应用程序中的变动就可以很好地管理起来。

    Advice通知

    Advice(通知)定义在连接点做什么,为切面增强提供织入接口。在Spring AOP中,它主要描述Spring AOP围绕方法调用而注入的切面行为。

    Pointcut切点

    Pointcut(切点)决定Advice通知应该作用于哪个连接点,也就是说通过Pointcut来定义需要增强的方法的集合,这些集合的选取可以按照一定的规则来完成。在这种情况下,Pointcut通常意味着标识方法,例如,这些需要增强的地方可以由某个正则表达式进行标识,或根据某个方法名进行匹配等。

    Advisor通知器

    完成对目标方法的切面增强设计(Advice)和关注点的设计(Pointcut)以后,需要一个对象把它们结合起来,完成这个作用的就是Advisor(通知器)。通过Advisor,可以定义应该使用哪个通知并在哪个关注点使用它,也就是说通过Advisor,把Advice和Pointcut结合起来,这个结合为使用IoC容器配置AOP应用,或者说即开即用地使用AOP基础设施,提供了便利。

    AOP实例

    项目中使用了logback来记录日志,需要生成线程流水号invokeNo来追踪线程执行过程,这里提供一种通过aop生成invokeNo的实现。

    1.pom.xml中引入aop的jar包:

    			<dependency>
    				<groupId>cglib</groupId>
    				<artifactId>cglib</artifactId>
    				<version>2.2.2</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.11</version>
    			</dependency>

    2.Advice类:

    public class InvokeNoAspect {
    
        /**
         * logger
         */
        private static final Logger LOGGER = LoggerFactory.getLogger(InvokeNoAspect.class);
    
        public Object process(ProceedingJoinPoint joinPoint) {
            try {
                MDC.put("invokeNo", UUID.randomUUID().toString().replaceAll("-", ""));
                Object obj = joinPoint.proceed();
                return obj;
            } catch (Throwable throwable) {
                LOGGER.error("MDC标识添加异常:", throwable);
                throw new RuntimeException("TraceIDAspect.process,MDC标识invokeNo添加异常");
            } finally {
                MDC.clear();
            }
        }
    }
    

    3.Advisor配置:

            <context:component-scan base-package="com.xxx"/>

    <!-- kafka监听类添加线程流水号invokeNo --> <bean id="logAspect" class="com.xxx.spring.InvokeNoAspect"/> <aop:config> <aop:pointcut id="pointcut" expression="execution(* com.xxx.biz..*.onMessage (..)) || execution(* com.xxx.web.task..*.doTask (..))"/> <aop:aspect ref="logAspect"> <aop:around pointcut-ref="pointcut" method="process"/> </aop:aspect> </aop:config>

    注:该配置必须放在bean注入配置后才起作用(如果是controller等类,需要在springmvc配置文件如dispatcher-servlet.xml中配置,如果是service类,需要在service bean注入的配置文件中配置)

    以上是通过execution中引入方法表达式形式来描述切入点pointcut,execution的详细描述如下:

    表达式 描述
    public * *(..) 任何公共方法的执行
    * cn.javass..IPointcutService.*() cn.javass包及所有子包下IPointcutService接口中的任何无参方法
    * cn.javass..*.*(..) cn.javass包及所有子包下任何类的任何方法
    * cn.javass..IPointcutService.*(*) cn.javass包及所有子包下IPointcutService接口的任何只有一个参数方法
    * (!cn.javass..IPointcutService+).*(..) 非“cn.javass包及所有子包下IPointcutService接口及子类型”的任何方法
    * cn.javass..IPointcutService+.*() cn.javass包及所有子包下IPointcutService接口及子类型的的任何无参方法
    * cn.javass..IPointcut*.test*(java.util.Date)

    cn.javass包及所有子包下IPointcut前缀类型的的以test开头的只有一个参数类型为java.util.Date的方法,注意该匹配是根据方法签名的参数类型进行匹配的,而不是根据执行时传入的参数类型决定的

    * cn.javass..IPointcut*.test*(..)  throws

     IllegalArgumentException, ArrayIndexOutOfBoundsException

    cn.javass包及所有子包下IPointcut前缀类型的的任何方法,且抛出IllegalArgumentException和ArrayIndexOutOfBoundsException异常

    * (cn.javass..IPointcutService+

    && java.io.Serializable+).*(..)

    任何实现了cn.javass包及所有子包下IPointcutService接口和java.io.Serializable接口的类型的任何方法
    @java.lang.Deprecated * *(..) 任何持有@java.lang.Deprecated注解的方法
    @java.lang.Deprecated @cn.javass..Secure  * *(..) 任何持有@java.lang.Deprecated和@cn.javass..Secure注解的方法
    (@cn.javass..Secure  *)  *(..) 任何返回值类型持有@cn.javass..Secure的方法
    *  (@cn.javass..Secure *).*(..) 任何定义方法的类型持有@cn.javass..Secure的方法
    * *(@cn.javass..Secure (*) , @cn.javass..Secure (*))

    任何签名带有两个参数的方法,且这个两个参数都被@ Secure标记了,

    如public void test(@Secure String str1, @Secure String str1);

    * *((@ cn.javass..Secure *))或

    * *(@ cn.javass..Secure *)

    任何带有一个参数的方法,且该参数类型持有@ cn.javass..Secure;

    如public void test(Model model);且Model类上持有@Secure注解

    * *(

    @cn.javass..Secure (@cn.javass..Secure *) ,

    @ cn.javass..Secure (@cn.javass..Secure *))

    任何带有两个参数的方法,且这两个参数都被@ cn.javass..Secure标记了;且这两个参数的类型上都持有@ cn.javass..Secure;

    * *(

    java.util.Map<cn.javass..Model, cn.javass..Model>

    , ..)

    任何带有一个java.util.Map参数的方法,且该参数类型是以< cn.javass..Model, cn.javass..Model >为泛型参数;注意只匹配第一个参数为java.util.Map,不包括子类型;

    如public void test(HashMap<Model, Model> map, String str);将不匹配,必须使用“* *(

    java.util.HashMap<cn.javass..Model,cn.javass..Model>

    , ..)”进行匹配;

    而public void test(Map map, int i);也将不匹配,因为泛型参数不匹配

    * *(java.util.Collection<@cn.javass..Secure *>)

    任何带有一个参数(类型为java.util.Collection)的方法,且该参数类型是有一个泛型参数,该泛型参数类型上持有@cn.javass..Secure注解;

    如public void test(Collection<Model> collection);Model类型上持有@cn.javass..Secure

    * *(java.util.Set<? extends HashMap>)

    任何带有一个参数的方法,且传入的参数类型是有一个泛型参数,该泛型参数类型继承自HashMap;

    Spring AOP目前测试不能正常工作

    * *(java.util.List<? super HashMap>)

    任何带有一个参数的方法,且传入的参数类型是有一个泛型参数,该泛型参数类型是HashMap的基类型;如public voi test(Map map);

    Spring AOP目前测试不能正常工作

    * *(*<@cn.javass..Secure *>)

    任何带有一个参数的方法,且该参数类型是有一个泛型参数,该泛型参数类型上持有@cn.javass..Secure注解;

    Spring AOP目前测试不能正常工作

    execution描述参考文章:https://blog.csdn.net/qq_23167527/article/details/78623639

    另外,Advisor的配置也可以通过对目标类添加注解的方式进行拦截:

        <!-- 事务框架 -->
    	<bean id="myServiceInterceptor" class="com.xxx.template.ServiceInterceptor">					 
    		<property name="transactionTemplate" ref="myTransactionTemplate" />
    	</bean>
    
    	<!-- 事务拦截器拦截以Service注解的bean -->
    	<aop:config>
    		<aop:pointcut id="transactionProfilePointcut" expression="@within(org.springframework.stereotype.Service)" />
    		<aop:advisor advice-ref="myServiceInterceptor"
    			pointcut-ref="transactionProfilePointcut" order="300" />
    	</aop:config>

    也可以类似这样:

        <!-- 秒级监控日志 -->
        <bean id="monitorAdviceExtends" class="com.xxx.template.MonitorAdviceExtends">
            <property name="preFix" value="${monitor.preFix}"/>
        </bean>
    
        <!-- 对beanName中以Biz结尾的类进行拦截 -->
        <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
            <property name="interceptorNames">
                <list>
                    <value>monitorAdviceExtends</value>
                </list>
            </property>
            <property name="beanNames">
                <value>*Biz</value>
            </property>
        </bean>
    
  • 相关阅读:
    Kakuro Extension HDU
    CodeForces
    HDU
    2019牛客暑期多校训练营(第二场)F.Partition problem
    UVA
    团队冲刺6
    团队冲刺4
    团队冲刺3
    团队冲刺2
    团队冲刺1
  • 原文地址:https://www.cnblogs.com/atai/p/9757976.html
Copyright © 2011-2022 走看看