手机用户请
横屏获取最佳阅读体验,REFERENCES中是本文参考的链接,如需要链接和更多资源,可以关注其他博客发布地址。
平台  | 地址  | 
|---|---|
CSDN  | https://blog.csdn.net/sinat_28690417  | 
简书  | https://www.jianshu.com/u/3032cc862300  | 
个人博客  | https://yiyuery.github.io/NoteBooks/  | 
正文
[Spring] Spring AOP 实现原理剖析(三)
Spring AOP 切面和切点
经过前文的介绍,我们可以看到AOP的增强可以针对一个类的所有方法进行增强(异常增强除外),那么,如何控制在类的指定方法进行增强?这便是接下来 AOP 的切点和切面的作用。
简言之,AOP编程的最主要工作,就是描述连接点的位置,并在对应位置织入增强。
Spring 通过Pointcut接口描述切点,其类图结果如下:
PointCut 通过 ClassFilter 和 MethodMather 构成,通过ClassFilter定位到某些特定方法上。ClassFilter 只有一个入参,用于判断被检测的类是否符合过滤条件。其中:
仅包含一个Advice,由于Advice本身包含了横切代码和连接点信息,所以其本身也是个简单的切面。
public interface PointcutAdvisor extends Advisor {
    /**
     * Get the Pointcut that drives this advisor.
     */
    Pointcut getPointcut();
}
主要实现类:
AbstractAspectJAdvice用于接收增强类public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedenceInformation, Serializable {
...
    /**
     * Key used in ReflectiveMethodInvocation userAtributes map for the current joinpoint.
     */
    protected static final String JOIN_POINT_KEY = JoinPoint.class.getName();
    /**
     * Lazily instantiate joinpoint for the current invocation.
     * Requires MethodInvocation to be bound with ExposeInvocationInterceptor.
     * <p>Do not use if access is available to the current ReflectiveMethodInvocation
     * (in an around advice).
     * @return current AspectJ joinpoint, or through an exception if we're not in a
     * Spring AOP invocation.
     */
    public static JoinPoint currentJoinPoint() {
        MethodInvocation mi = ExposeInvocationInterceptor.currentInvocation();
        if (!(mi instanceof ProxyMethodInvocation)) {
            throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
        }
        ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
        JoinPoint jp = (JoinPoint) pmi.getUserAttribute(JOIN_POINT_KEY);
        if (jp == null) {
            jp = new MethodInvocationProceedingJoinPoint(pmi);
            pmi.setUserAttribute(JOIN_POINT_KEY, jp);
        }
        return jp;
    }
    //...
JdkRegexpMethodPointcut构造切点。/**
    * Initialize the singleton Pointcut held within this Advisor.
    */
@Override
public Pointcut getPointcut() {
    synchronized (this.pointcutMonitor) {
        if (this.pointcut == null) {
            this.pointcut = createPointcut();
            if (this.patterns != null) {
                this.pointcut.setPatterns(this.patterns);
            }
        }
        return this.pointcut;
    }
}
/**
    * Create the actual pointcut: By default, a {@link JdkRegexpMethodPointcut}
    * will be used.
    * @return the Pointcut instance (never {@code null})
    */
protected AbstractRegexpMethodPointcut createPointcut() {
    return new JdkRegexpMethodPointcut();
}
引介切点定义的特殊切面,应用于类层面,扩展类的属性和方法,引介切点使用ClassFilter来定义,顺带提下,其余集中增强对应的切点,都是方法层面的,通过MethodMather来定义。
定位切点,构造增强,织入切面
切面定义
public class BusinessLogHandlerStaticAdvisor extends StaticMethodMatcherPointcutAdvisor {
    @Override
    public boolean matches(Method method, Class<?> targetClass) {
        return method.getName().startsWith("simpleAdd");
    }
    @Override
    public ClassFilter getClassFilter() {
        return new ClassFilter() {
            @Override
            public boolean matches(Class<?> clazz) {
                return PersonManagerServiceImpl.class.isAssignableFrom(clazz);
            }
        };
    }
}
Spring 配置
<?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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--1、被增强类-->
    <bean id="target" class="com.example.spring.aop.service.impl.PersonManagerServiceImpl"/>
    <!--2、增强类-->
    <bean id="businessLogHandlerBeforeAdvice" class="com.example.spring.aop.advice.BusinessLogHandlerBeforeAdvice"/>
    <!--3、代理工厂定义-->
    <!--3.1 指定代理的接口-->
    <!--3.2 指定使用的增强-->
    <!--3.3 指定对哪个bean进行代理-->
   <!-- <bean id="personManagerImpl" class="org.springframework.aop.framework.ProxyFactoryBean"
          p:proxyInterfaces="com.example.spring.aop.service.IPersonManagerService"
          p:interceptorNames="businessLogHandlerBeforeAdvice"
          p:target-ref="target"/>-->
    <!--定义切面-->
    <bean id="businessLogHandlerStaticAdvisor" class="com.example.spring.aop.advisor.BusinessLogHandlerStaticAdvisor"
          p:advice-ref="businessLogHandlerBeforeAdvice"/>
    <!--定义公共抽象类-->
    <bean id="parentAdvisor" abstract="true" class="org.springframework.aop.framework.ProxyFactoryBean"
          p:interceptorNames="businessLogHandlerStaticAdvisor"
          p:proxyTargetClass="true"
          />
    <bean id="personManagerImpl" parent="parentAdvisor"
    p:target-ref="target"/>
</beans>
注释部分为原先切点定义逻辑,可以看出增加了切面定义,但是切面引入了切点,原来的方式属于增强定义,增强逻辑中本身就包含了连接点信息,即一般普通切面。
测试输出
 /**
     * 静态普通方法匹配切面
     */
    @Test
    public void testStaticMethodAdvisor(){
        ApplicationContext context = new ClassPathXmlApplicationContext("config/spring/advisor/aop-before-advice-advisor.xml");
        PersonManagerServiceImpl bean = (PersonManagerServiceImpl) context.getBean("personManagerImpl");
        bean.deletePerson();
        log.info("--------------------------");
        bean.simpleAddPerson();
    }
//20:04:01.318 [main] INFO com.example.spring.aop.service.impl.PersonManagerServiceImpl - 模拟人员数据删除
//20:04:04.321 [main] INFO com.example.spring.aop.service.impl.PersenMangaerServiceImplAdvisorTest - --------------------------
//20:04:04.326 [main] INFO com.example.spring.aop.simple.BusinessLogMonitor - begin monitor...
//20:04:04.326 [main] INFO com.example.spring.aop.service.impl.PersonManagerServiceImpl - 模拟人员数据添加
通过日志可以看出实现了指定方法(开头为simpleAdd的方法)的增强。
切面定义
通过默认实现类org.springframework.aop.support.RegexpMethodPointcutAdvisor实现
Spring 配置
<?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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--1、被增强类-->
    <bean id="target" class="com.example.spring.aop.service.impl.PersonManagerServiceImpl"/>
    <!--2、增强类-->
    <bean id="businessLogHandlerBeforeAdvice" class="com.example.spring.aop.advice.BusinessLogHandlerBeforeAdvice"/>
    <!--3、代理工厂定义-->
    <!--3.1 指定代理的接口-->
    <!--3.2 指定使用的增强-->
    <!--3.3 指定对哪个bean进行代理-->
   <!-- <bean id="personManagerImpl" class="org.springframework.aop.framework.ProxyFactoryBean"
          p:proxyInterfaces="com.example.spring.aop.service.IPersonManagerService"
          p:interceptorNames="businessLogHandlerBeforeAdvice"
          p:target-ref="target"/>-->
    <!--定义切面-->
    <bean id="businessLogHandlerRegexAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"
          p:advice-ref="businessLogHandlerBeforeAdvice"
          p:pattern=".*Add.*"/>
    <bean id="parentAdvisor" abstract="true" class="org.springframework.aop.framework.ProxyFactoryBean"
          p:interceptorNames="businessLogHandlerRegexAdvisor"
          p:proxyTargetClass="true"
          />
    <bean id="personManagerImpl" parent="parentAdvisor"  p:target-ref="target"/>
</beans>
测试输出
 /**
     * 静态正则表达式方法匹配切面
     */
    @Test
    public void testRegexMethodAdvisor() {
        ApplicationContext context = new ClassPathXmlApplicationContext("config/spring/advisor/aop-before-advice-regex-advisor.xml");
        PersonManagerServiceImpl bean = (PersonManagerServiceImpl)context.getBean("personManagerImpl");
        bean.deletePerson();
        log.info("--------------------------");
        bean.simpleAddPerson();
    }
    //20:18:10.789 [main] INFO com.example.spring.aop.service.impl.PersonManagerServiceImpl - 模拟人员数据删除
    //20:18:13.794 [main] INFO com.example.spring.aop.service.impl.PersonMangaerServiceImplAdvisorTest - --------------------------
    //20:18:13.800 [main] INFO com.example.spring.aop.simple.BusinessLogMonitor - begin monitor...
    //20:18:13.801 [main] INFO com.example.spring.aop.service.impl.PersonManagerServiceImpl - 模拟人员数据添加
通过日志可以看出,匹配正则.*Add.*的方法才会被增强。
切面定义
@Slf4j
public class BusinessLogHandlerDynamicAdvisorPointcut extends DynamicMethodMatcherPointcut {
    @Override
    public boolean matches(Method method, Class<?> targetClass, Object... args) {
        log.info("BusinessLogHandlerDynamicAdvisor 动态检查-1: "+ method.getName());
        return method.getName().startsWith("simple");
    }
    @Override
    public boolean matches(Method method, Class<?> targetClass) {
        log.info("BusinessLogHandlerDynamicAdvisor 静态检查-1: "+ method.getName());
        return method.getName().startsWith("simple");
    }
    @Override
    public ClassFilter getClassFilter() {
        log.info("BusinessLogHandlerDynamicAdvisor 静态检查-2: getClassFilter");
        return PersonManagerServiceImpl.class::isAssignableFrom;
    }
}
与前面两种切面有点儿不一样的是,动态切面的定义是基于默认切面,定义切点逻辑来扩展实现的。而非直接提供对应实现类。主要也是考虑到动态逻辑设计的复杂性和可扩展性。像正则表达式和静态方法匹配,其切点的定义策略不会有太大差异。
Spring 配置
<?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:p="http://www.springframework.org/schema/p"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
    <!--1、被增强类-->
    <bean id="target" class="com.example.spring.aop.service.impl.PersonManagerServiceImpl"/>
    <!--2、增强类-->
    <bean id="businessLogHandlerBeforeAdvice" class="com.example.spring.aop.advice.BusinessLogHandlerBeforeAdvice"/>
    <!--3、代理工厂定义-->
    <!--3.1 指定代理的接口-->
    <!--3.2 指定使用的增强-->
    <!--3.3 指定对哪个bean进行代理-->
   <!-- <bean id="personManagerImpl" class="org.springframework.aop.framework.ProxyFactoryBean"
          p:proxyInterfaces="com.example.spring.aop.service.IPersonManagerService"
          p:interceptorNames="businessLogHandlerBeforeAdvice"
          p:target-ref="target"/>-->
    <!--定义切面-->
    <bean id="businessLogHandlerDynamicAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor"
          p:advice-ref="businessLogHandlerBeforeAdvice">
        <property name="pointcut">
            <bean class="com.example.spring.aop.advisor.BusinessLogHandlerDynamicAdvisorPointcut"/>
        </property>
    </bean>
    <bean id="parentAdvisor" abstract="true" class="org.springframework.aop.framework.ProxyFactoryBean"
          p:interceptorNames="businessLogHandlerDynamicAdvisor"
          p:proxyTargetClass="true"
          />
    <bean id="personManagerImpl" parent="parentAdvisor"  p:target-ref="target"/>
</beans>
测试输出
 /**
     *动态切面
     */
    @Test
    public void testDynamicMethodAdvisor() {
        ApplicationContext context = new ClassPathXmlApplicationContext("config/spring/advisor/aop-before-advice-dynamic-advisor.xml");
        PersonManagerServiceImpl bean = (PersonManagerServiceImpl)context.getBean("personManagerImpl");
        log.info("--------------------------");
        bean.deletePerson();
        log.info("--------------------------");
        bean.simpleAddPerson();
        log.info("--------------------------");
        bean.simpleAddPerson();
    }
//20:31:52.546 [main] DEBUG org.springframework.aop.framework.ProxyFactoryBean - Advice has changed; recaching singleton instance
//20:31:52.649 [main] INFO com.example.spring.aop.advisor.BusinessLogHandlerDynamicAdvisorPointcut - BusinessLogHandlerDynamicAdvisor 静态检查-2: getClassFilter
//20:31:52.651 [main] INFO com.example.spring.aop.advisor.BusinessLogHandlerDynamicAdvisorPointcut - BusinessLogHandlerDynamicAdvisor 静态检查-1: addPerson
//20:31:52.651 [main] INFO com.example.spring.aop.advisor.BusinessLogHandlerDynamicAdvisorPointcut - BusinessLogHandlerDynamicAdvisor 静态检查-2: getClassFilter
//20:31:52.651 [main] INFO com.example.spring.aop.advisor.BusinessLogHandlerDynamicAdvisorPointcut - BusinessLogHandlerDynamicAdvisor 静态检查-1: modifyPerson
//20:31:52.651 [main] INFO com.example.spring.aop.advisor.BusinessLogHandlerDynamicAdvisorPointcut - BusinessLogHandlerDynamicAdvisor 静态检查-2: getClassFilter
//20:31:52.651 [main] INFO com.example.spring.aop.advisor.BusinessLogHandlerDynamicAdvisorPointcut - BusinessLogHandlerDynamicAdvisor 静态检查-1: deleteThrowException
//20:31:52.651 [main] INFO com.example.spring.aop.advisor.BusinessLogHandlerDynamicAdvisorPointcut - BusinessLogHandlerDynamicAdvisor 静态检查-2: getClassFilter
//20:31:52.651 [main] INFO com.example.spring.aop.advisor.BusinessLogHandlerDynamicAdvisorPointcut - BusinessLogHandlerDynamicAdvisor 静态检查-1: deletePerson
//20:31:52.651 [main] INFO com.example.spring.aop.advisor.BusinessLogHandlerDynamicAdvisorPointcut - BusinessLogHandlerDynamicAdvisor 静态检查-2: getClassFilter
//20:31:52.651 [main] INFO com.example.spring.aop.advisor.BusinessLogHandlerDynamicAdvisorPointcut - BusinessLogHandlerDynamicAdvisor 静态检查-1: simpleAddPerson
//20:31:52.653 [main] INFO com.example.spring.aop.advisor.BusinessLogHandlerDynamicAdvisorPointcut - BusinessLogHandlerDynamicAdvisor 静态检查-2: getClassFilter
//20:31:52.653 [main] INFO com.example.spring.aop.advisor.BusinessLogHandlerDynamicAdvisorPointcut - BusinessLogHandlerDynamicAdvisor 静态检查-1: toString
//20:31:52.653 [main] INFO com.example.spring.aop.advisor.BusinessLogHandlerDynamicAdvisorPointcut - BusinessLogHandlerDynamicAdvisor 静态检查-2: getClassFilter
//20:31:52.653 [main] INFO com.example.spring.aop.advisor.BusinessLogHandlerDynamicAdvisorPointcut - BusinessLogHandlerDynamicAdvisor 静态检查-1: clone
//20:31:52.678 [main] INFO com.example.spring.aop.service.impl.PersonMangaerServiceImplAdvisorTest - --------------------------
//20:31:52.678 [main] INFO com.example.spring.aop.advisor.BusinessLogHandlerDynamicAdvisorPointcut - BusinessLogHandlerDynamicAdvisor 静态检查-2: getClassFilter
//20:31:52.678 [main] INFO com.example.spring.aop.advisor.BusinessLogHandlerDynamicAdvisorPointcut - BusinessLogHandlerDynamicAdvisor 静态检查-1: deletePerson
//20:31:52.693 [main] INFO com.example.spring.aop.service.impl.PersonManagerServiceImpl - 模拟人员数据删除
//20:31:55.698 [main] INFO com.example.spring.aop.service.impl.PersonMangaerServiceImplAdvisorTest - --------------------------
//20:31:55.698 [main] INFO com.example.spring.aop.advisor.BusinessLogHandlerDynamicAdvisorPointcut - BusinessLogHandlerDynamicAdvisor 静态检查-2: getClassFilter
//20:31:55.698 [main] INFO com.example.spring.aop.advisor.BusinessLogHandlerDynamicAdvisorPointcut - BusinessLogHandlerDynamicAdvisor 静态检查-1: simpleAddPerson
//20:31:55.701 [main] INFO com.example.spring.aop.advisor.BusinessLogHandlerDynamicAdvisorPointcut - BusinessLogHandlerDynamicAdvisor 动态检查-1: simpleAddPerson
//20:31:55.702 [main] INFO com.example.spring.aop.simple.BusinessLogMonitor - begin monitor...
//20:31:55.702 [main] INFO com.example.spring.aop.service.impl.PersonManagerServiceImpl - 模拟人员数据添加
//20:31:58.703 [main] INFO com.example.spring.aop.service.impl.PersonMangaerServiceImplAdvisorTest - --------------------------
//20:31:58.703 [main] INFO com.example.spring.aop.advisor.BusinessLogHandlerDynamicAdvisorPointcut - BusinessLogHandlerDynamicAdvisor 动态检查-1: simpleAddPerson
//20:31:58.703 [main] INFO com.example.spring.aop.simple.BusinessLogMonitor - begin monitor...
//20:31:58.703 [main] INFO com.example.spring.aop.service.impl.PersonManagerServiceImpl - 模拟人员数据添加
通过日志可以看出,每次切点匹配到的方法都会执行动态检查,而静态方法检查只会执行一次。主要实检查方法签名是否匹配。
切面定义
@Slf4j
public class BusinessLogHandlerComposablePointcut extends ComposablePointcut{
    public BusinessLogHandlerComposablePointcut() {
        Pointcut simpleAddPointCut = new ControlFlowPointcut(PersonManagerProxyService.class, "simpleAdd");
        Pointcut nameMatchMethodPointcut = new NameMatchMethodPointcut();
        ((NameMatchMethodPointcut)nameMatchMethodPointcut).setMappedName("simpleAddPersonWithFilter");
        this.intersection(simpleAddPointCut).intersection(nameMatchMethodPointcut);
    }
}
//定义流程节点
@AllArgsConstructor
public class PersonManagerProxyService {
    private IPersonManagerService personManagerService;
    public void simpleAdd(){
        personManagerService.simpleAddPerson();
        //personManagerService.simpleAddPersonWithFilter();
    }
}
和动态切面一样,流程切面也是直接定义切点后,基于默认的切面实现类扩展,来实现流程切面的。
Spring 配置
<?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:p="http://www.springframework.org/schema/p"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
    <!--1、被增强类-->
    <bean id="target" class="com.example.spring.aop.service.impl.PersonManagerServiceImpl"/>
    <!--2、增强类-->
    <bean id="businessLogHandlerBeforeAdvice" class="com.example.spring.aop.advice.BusinessLogHandlerBeforeAdvice"/>
    <!--3、代理工厂定义-->
    <!--3.1 指定代理的接口-->
    <!--3.2 指定使用的增强-->
    <!--3.3 指定对哪个bean进行代理-->
   <!-- <bean id="personManagerImpl" class="org.springframework.aop.framework.ProxyFactoryBean"
          p:proxyInterfaces="com.example.spring.aop.service.IPersonManagerService"
          p:interceptorNames="businessLogHandlerBeforeAdvice"
          p:target-ref="target"/>-->
    <!--定义流程切点-->
    <bean id="controlFlowPointcut" class="org.springframework.aop.support.ControlFlowPointcut">
        <!--流程节点代理执行类-->
        <constructor-arg type="java.lang.Class" value="com.example.spring.aop.service.impl.PersonManagerProxyService"/>
        <!--定义切点方法-->
        <constructor-arg type="java.lang.String" value="simpleAdd"/>
    </bean>
    <!--定义切面-->
    <bean id="businessLogHandlerControlFlowAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor"
          p:advice-ref="businessLogHandlerBeforeAdvice">
        <property name="pointcut" ref="controlFlowPointcut"/>
    </bean>
    <!--抽象切面父类-->
    <bean id="parentAdvisor" abstract="true" class="org.springframework.aop.framework.ProxyFactoryBean"
          p:interceptorNames="businessLogHandlerControlFlowAdvisor"
          p:proxyTargetClass="true"
          />
    <!--实际执行类-->
    <bean id="personManagerImpl" parent="parentAdvisor"  p:target-ref="target"/>
</beans>
测试输出
/**
     * 流程切面
     */
    @Test
    public void testControlFlowAdvisor() {
        ApplicationContext context = new ClassPathXmlApplicationContext("config/spring/advisor/aop-before-advice-flow-advisor.xml");
        PersonManagerServiceImpl bean = (PersonManagerServiceImpl)context.getBean("personManagerImpl");
        log.info("--------------------------");
        bean.deletePerson();
        log.info("--------------------------");
        bean.simpleAddPerson();
        log.info("--------------------------");
        PersonManagerProxyService personManagerProxyService = new PersonManagerProxyService(bean);
        personManagerProxyService.simpleAdd();
    }
    //20:47:35.962 [main] DEBUG org.springframework.aop.framework.ProxyFactoryBean - Advice has changed; recaching singleton instance
    //20:47:36.070 [main] INFO com.example.spring.aop.service.impl.PersonMangaerServiceImplAdvisorTest - --------------------------
    //20:47:36.084 [main] INFO com.example.spring.aop.service.impl.PersonManagerServiceImpl - 模拟人员数据删除
    //20:47:39.086 [main] INFO com.example.spring.aop.service.impl.PersonMangaerServiceImplAdvisorTest - --------------------------
    //20:47:39.086 [main] INFO com.example.spring.aop.service.impl.PersonManagerServiceImpl - 模拟人员数据添加
    //20:47:42.087 [main] INFO com.example.spring.aop.service.impl.PersonMangaerServiceImplAdvisorTest - --------------------------
    //20:47:42.088 [main] INFO com.example.spring.aop.simple.BusinessLogMonitor - begin monitor...
    //20:47:42.089 [main] INFO com.example.spring.aop.service.impl.PersonManagerServiceImpl - 模拟人员数据添加
通过日志可以看出,只有被定义为特定流程的切点PersonManagerProxyService.simpleAdd满足条件时,其方法才会被增强。
切面定义
@Slf4j
public class BusinessLogHandlerComposablePointcut extends ComposablePointcut{
    public BusinessLogHandlerComposablePointcut() {
        Pointcut simpleAddPointCut = new ControlFlowPointcut(PersonManagerProxyService.class, "simpleAdd");
        Pointcut nameMatchMethodPointcut = new NameMatchMethodPointcut();
        ((NameMatchMethodPointcut)nameMatchMethodPointcut).setMappedName("simpleAddPersonWithFilter");
        this.intersection(simpleAddPointCut).intersection(nameMatchMethodPointcut);
    }
}
和动态切面一样,复合切面也是直接定义切点后,基于默认的切面实现类扩展,来实现流程切面的。特别的是,复合切面的切点可以整合好几种不同的切点共同编织切面逻辑。
Spring 配置
<?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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--1、被增强类-->
    <bean id="target" class="com.example.spring.aop.service.impl.PersonManagerServiceImpl"/>
    <!--2、增强类-->
    <bean id="businessLogHandlerBeforeAdvice" class="com.example.spring.aop.advice.BusinessLogHandlerBeforeAdvice"/>
    <!--3、代理工厂定义-->
    <!--3.1 指定代理的接口-->
    <!--3.2 指定使用的增强-->
    <!--3.3 指定对哪个bean进行代理-->
   <!-- <bean id="personManagerImpl" class="org.springframework.aop.framework.ProxyFactoryBean"
          p:proxyInterfaces="com.example.spring.aop.service.IPersonManagerService"
          p:interceptorNames="businessLogHandlerBeforeAdvice"
          p:target-ref="target"/>-->
    <bean id="composablePointcut" class="com.example.spring.aop.advisor.BusinessLogHandlerComposablePointcut"/>
    <!--定义切面-->
    <bean id="businessLogHandlerComposableAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor"
          p:pointcut-ref="composablePointcut"
          p:advice-ref="businessLogHandlerBeforeAdvice"/>
    <!--定义公共抽象类-->
    <bean id="parentAdvisor" abstract="true" class="org.springframework.aop.framework.ProxyFactoryBean"
          p:interceptorNames="businessLogHandlerComposableAdvisor"
          p:proxyTargetClass="true"/>
    <bean id="personManagerImpl" parent="parentAdvisor"   p:target-ref="target"/>
</beans>
测试输出
 /**
     * 复合切面
     */
    @Test
    public void testComposablePointcutAdvisor() {
        ApplicationContext context = new ClassPathXmlApplicationContext("config/spring/advisor/aop-before-composable-advisor.xml");
        PersonManagerServiceImpl bean = (PersonManagerServiceImpl)context.getBean("personManagerImpl");
        log.info("--------------------------");
        bean.deletePerson();
        log.info("--------------------------");
        bean.simpleAddPerson();
        log.info("--------------------------");
        PersonManagerProxyService personManagerProxyService = new PersonManagerProxyService(bean);
        personManagerProxyService.simpleAdd();
    }
    //21:28:10.708 [main] INFO com.example.spring.aop.service.impl.PersonMangaerServiceImplAdvisorTest - --------------------------
    //21:28:10.724 [main] INFO com.example.spring.aop.service.impl.PersonManagerServiceImpl - 模拟人员数据删除
    //21:28:13.727 [main] INFO com.example.spring.aop.service.impl.PersonMangaerServiceImplAdvisorTest - --------------------------
    //21:28:13.727 [main] INFO com.example.spring.aop.service.impl.PersonManagerServiceImpl - 模拟人员数据添加
    //21:28:16.728 [main] INFO com.example.spring.aop.service.impl.PersonMangaerServiceImplAdvisorTest - --------------------------
    //21:28:16.728 [main] INFO com.example.spring.aop.service.impl.PersonManagerServiceImpl - 模拟人员数据添加
    //21:28:19.737 [main] INFO com.example.spring.aop.monitor.BusinessLogMonitor - > simpleAddPersonWithFilter: begin monitor...
    //21:28:19.738 [main] INFO com.example.spring.aop.service.impl.PersonManagerServiceImpl - 模拟人员数据添加
从日子可以看出,只有满足流程切点和静态方法(NameMatchMethodPointcut是StaticMethodMatcherPointcut的一个子类)切点同时满足匹配逻辑的情况下,对应方法才会被增强。
切面定义
引介增强由于是面对类层面的,所以,对应切面也有默认的实现类,只需要向默认的切面实现类中,传入引介增强类即可。
Spring 配置
<?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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--1、被增强类-->
    <bean id="target" class="com.example.spring.aop.service.impl.PersonManagerServiceImpl"/>
    <!--2、增强类-->
    <bean id="businessLogHandlerIntroduceAdvice" class="com.example.spring.aop.advice.introduce.BusinessLogHandlerIntroduceAdvice"/>
    <!--3、代理工厂定义-->
    <!--3.1 指定代理的接口-->
    <!--3.2 指定使用的增强-->
    <!--3.3 指定对哪个bean进行代理-->
   <!-- <bean id="personManagerImpl" class="org.springframework.aop.framework.ProxyFactoryBean"
          p:proxyInterfaces="com.example.spring.aop.service.IPersonManagerService"
          p:interceptorNames="businessLogHandlerBeforeAdvice"
          p:target-ref="target"/>-->
    <!--定义切面-->
    <bean id="businessLogHandlerIntroductionAdvisor" class="org.springframework.aop.support.DefaultIntroductionAdvisor">
        <constructor-arg ref="businessLogHandlerIntroduceAdvice"/>
    </bean>
    <!--定义公共抽象类-->
    <bean id="parentAdvisor" abstract="true" class="org.springframework.aop.framework.ProxyFactoryBean"
          p:interceptorNames="businessLogHandlerIntroductionAdvisor"
          p:proxyTargetClass="true"
          />
    <bean id="personManagerImpl" parent="parentAdvisor"
    p:target-ref="target"/>
</beans>
测试输出
 /**
     * 引介切面
     */
    @Test
    public void testIntroduceAdvisor() {
        ApplicationContext context = new ClassPathXmlApplicationContext("config/spring/advisor/aop-before-introduce-advisor.xml");
        PersonManagerServiceImpl bean = (PersonManagerServiceImpl)context.getBean("personManagerImpl");
        log.info("--------------------------");
        bean.deletePerson();
        BusinessLogHandlerIntroduceSwitch businessLogHandlerIntroduceSwitch = (BusinessLogHandlerIntroduceSwitch) bean;
        businessLogHandlerIntroduceSwitch.setSwitch(true);
        bean.deletePerson();
    }
    //22:14:59.875 [main] INFO com.example.spring.aop.service.impl.PersonManagaerServiceImplAdvisorTest - --------------------------
    //22:14:59.892 [main] INFO com.example.spring.aop.service.impl.PersonManagerServiceImpl - 模拟人员数据删除
    //22:15:02.896 [main] INFO com.example.spring.aop.monitor.BusinessLogMonitor - > deletePerson: begin monitor...
    //22:15:02.897 [main] INFO com.example.spring.aop.service.impl.PersonManagerServiceImpl - 模拟人员数据删除
    //22:15:05.902 [main] INFO com.example.spring.aop.monitor.BusinessLogMonitor - > end monitor....
沿用之前定义的引介增强定义BusinessLogHandlerIntroduceSwitch,我们织入默认的切面实现类org.springframework.aop.support.DefaultIntroductionAdvisor,便可完成引介切面的定义。
通过上述介绍,我们总结下切点和切面的特征,我们AOP的编程核心目的是指定方法或类对其进行增强。
AOP。