Spring切面

《一、静态代理匹配切面》

一、 RegexpMethodPointcutAdvisor 静态正则表达式匹配切面

目标类:

package com.pointcut;

/**
 * @author JCL
 * @date 2019-12-11 22:18
 */
public class GreetWaiter {
    public void greeting(){
        System.out.println("welcome to china");
    }
}

前置增强类:

package com.pointcut;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

/**
 * 前置增强类
 * @author JCL
 * @date 2019-12-11 22:24
 */

public class BeforeAdvice implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println("===执行了beforeAdvice增强类方法====");
    }
}

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: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-3.0.xsd">
<!--目标类bean-->
    <bean id="greetingWaiter" class="com.pointcut.GreetWaiter"/>
<!--增强类bean-->
    <bean id="beforeAdvice" class="com.pointcut.BeforeAdvice"/>
<!--    切面-->
    <bean id="regexAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"
          p:advice-ref="beforeAdvice"> <!--为切面添加增强类,增强类一般配合切面使用-->
        <property name="patterns">
            <list>
            <!--  配置目标类方法的正则表达式   -->
                <value>.*greeting.*</value> 
            </list>
        </property>
    </bean>
<!--          p:pattern=".*greeting.*"/>-->

    <bean id="waiterGreet" class="org.springframework.aop.framework.ProxyFactoryBean"
          p:interceptorNames="regexAdvisor" <!--切面bean-->
          p:target-ref="greetingWaiter" <!--代理目标类的bean-->
          p:proxyTargetClass="true"/> <!--代理目标是否为类-->

</beans>

测试类:


    @Test
    public void test18(){
        ClassPathXmlApplicationContext context=
                new ClassPathXmlApplicationContext(new String[]{"pointcut.xml"});
//此时执行的不是目标类的bean了,而是代理类的bean
        GreetWaiter greetWaiter=(GreetWaiter)context.getBean("waiterGreet");
        greetWaiter.greeting();
    }

结果输出:

===执行了beforeAdvice增强类方法====
welcome to china

二、StaticMethodMatcherPointcutAdvisor  静态普通方法名匹配切面

除了切面配置,其他类同上。

创建切面:

package com.pointcut;

import org.springframework.aop.ClassFilter;
import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor;

import java.lang.reflect.Method;

/**
 * @author JCL
 * @date 2019-12-12 06:48
 */
public class MethodPointcutAdvisor extends StaticMethodMatcherPointcutAdvisor {
    @Override
    public boolean matches(Method method, Class<?> aClass) {
        if ("greeting".equals(method.getName())){
            return true;
        }
        return false;
    }


//    不覆盖此方法则是在所有类中寻找匹配方法
    @Override
    public ClassFilter getClassFilter() {
       return new ClassFilter(){
           @Override
           public boolean matches(Class aClass) {
//isAssignableFrom方法判断两个类是否是父子类关系
               return GreetWaiter.class.isAssignableFrom(aClass);

           }
       };
    }

}

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: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-3.0.xsd">
<!--目标类bean-->
    <bean id="greetingWaiter" class="com.pointcut.GreetWaiter"/>
<!--增强类bean-->
    <bean id="beforeAdvice" class="com.pointcut.BeforeAdvice"/>
<!--    切面-->
    <bean id="methodPointcutAdvisor" class="com.pointcut.MethodPointcutAdvisor"
          p:advice-ref="beforeAdvice"/>


    <bean id="waiterGreet" class="org.springframework.aop.framework.ProxyFactoryBean"
          p:interceptorNames="methodPointcutAdvisor"
          p:target-ref="greetingWaiter"
          p:proxyTargetClass="true"/> <!--代理目标是否为类-->

</beans>

使用StaticMethodMatcherPointcutAdvisor需要写切面类,而使用 RegexpMethodMatcherPointcutAdvisor直接配置bean即可。

《二、动态代理匹配切面》

动态代理对性能影响比较大,所以一般都先用静态代理过滤以下再执行动态代理。

动态代理一般用 DynamicMethodMatcherPointcut创建切点和DefaultPointcutAdvisor创建切面配合使用

目标类:

package com.pointcut;

/**
 * @author JCL
 * @date 2019-12-11 22:18
 */
public class GreetWaiter {
    public void greeting(){
        System.out.println("welcome to china");
    }


    public void greeting2(String name){
        System.out.println("welcome"+name+" to test 动态切点");
    }


}

创建动态代理切点(not 切面):

package com.pointcut.DynamicPointcut;

import com.pointcut.GreetWaiter;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.support.DynamicMethodMatcherPointcut;
import org.springframework.lang.Nullable;

import java.lang.reflect.Method;

/**
 * 定义动态切点
 * @author JCL
 * @date 2019-12-12 07:46
 */
public class DynamicPointcut extends DynamicMethodMatcherPointcut {
    //对类进行静态节点检查
    public ClassFilter getClassFilter() {
        return new ClassFilter(){

            @Override
            public boolean matches(Class<?> aClass) {
                //判断是否是GreetWaiter类或其子类
                return GreetWaiter.class.isAssignableFrom(aClass);
            }
        };

    }

    //对方法进行静态切点检查
    public boolean matches(Method method, @Nullable Class<?> targetClass) {
        return method.getName().equals("greeting2");
    }


    //进行动态切点检查
    @Override
    public boolean matches(Method method, Class<?> aClass, Object... objects) {
        String arg=(String) objects[0];
        return "john".equals(arg);
    }
}

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: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-3.0.xsd">
<!--目标类bean-->
    <bean id="greetingWaiter" class="com.pointcut.GreetWaiter"/>
<!--增强类bean-->
    <bean id="beforeAdvice" class="com.pointcut.BeforeAdvice"/>
<!--    切点-->
    <bean id="dynamicPointcut" class="com.pointcut.DynamicPointcut.DynamicPointcut"/>
<!--    切面-->
    <bean id="dynamicPointcutAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor"
          p:pointcut-ref="dynamicPointcut"
          p:advice-ref="beforeAdvice"/>


    <bean id="waiterGreet" class="org.springframework.aop.framework.ProxyFactoryBean"
          p:interceptorNames="dynamicPointcutAdvisor"
          p:target-ref="greetingWaiter"
          p:proxyTargetClass="true"/> <!--代理目标是否为类-->

</beans>

测试类:

    @Test
    public void test19(){
        ClassPathXmlApplicationContext context=
                new ClassPathXmlApplicationContext(new String[]{"dynamicPointcut.xml"});
        GreetWaiter greetWaiter=(GreetWaiter)context.getBean("waiterGreet");
        greetWaiter.greeting2("john");
    }

输出:

===执行了beforeAdvice增强类方法====
welcomejohn to test 动态切点

《三、流程切面》

流程切点:由某个方法直接或间接发起调用的其他方法。

我的理解:对某个类所有或部分方法的代理。

流程切面和动态切面一样,都性能影响很大。

要代理的类:

package com.pointcut;

/**
 * @author JCL
 * @date 2019-12-11 22:18
 */
public class GreetWaiter {
    public void greeting(){
        System.out.println("welcome to china");
    }


    public void greeting2(String name){
        System.out.println("welcome "+name+" 执行了greeting2方法");
    }


}

代理类:

package com.pointcut.controlFlowPointcut;

import com.pointcut.GreetWaiter;

/**
 * @author JCL
 * @date 2019-12-22 11:04
 */
public class WaiterDelegate {
    private GreetWaiter greetWaiter;

    public void services(String name){
        greetWaiter.greeting();
        greetWaiter.greeting2(name);
    }

    public void setGreetWaiter(GreetWaiter greetWaiter) {
        this.greetWaiter = greetWaiter;
    }
}

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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!--目标类bean-->
    <bean id="greetingWaiter" class="com.pointcut.GreetWaiter"/>
<!--增强类bean-->
    <bean id="beforeAdvice" class="com.pointcut.BeforeAdvice"/>
<!--    流程切点-->
    <bean id="controlFlowPointcut" class="org.springframework.aop.support.ControlFlowPointcut">
        <constructor-arg type="java.lang.Class" value="com.pointcut.controlFlowPointcut.WaiterDelegate"/>
        <constructor-arg type="java.lang.String" value="services"/>
    </bean>

<!--    切面-->
    <bean id="controlFlowAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor"
          p:pointcut-ref="controlFlowPointcut"
          p:advice-ref="beforeAdvice"/>

    <bean id="waiterGreet" class="org.springframework.aop.framework.ProxyFactoryBean"
          p:interceptorNames="controlFlowAdvisor"
          p:target-ref="greetingWaiter"
          p:proxyTargetClass="true"/> <!--代理目标是否为类-->

</beans>

测试类:

    @Test
    public void test22(){
        ClassPathXmlApplicationContext context=
                new ClassPathXmlApplicationContext(new String[]{"controlFlowPointcut.xml"});
        GreetWaiter greetWaiter=(GreetWaiter)context.getBean("waiterGreet");
        greetWaiter.greeting();
        greetWaiter.greeting2("ff");

        WaiterDelegate waiterDelegate=new WaiterDelegate();
        waiterDelegate.setGreetWaiter(greetWaiter);
        waiterDelegate.services("xuehuan");



    }

输出:

welcome to china
welcome ff 执行了greeting2方法
===执行了beforeAdvice增强类方法====
welcome to china
===执行了beforeAdvice增强类方法====
welcome 滴滴 执行了greeting2方法

可以看到直接调用 GreetWaiter类的两个方法无法织入增强,

调用WaiterDelegate#services可以对GreetWaiter类的方法织入增强

《四、复合切点切面》

复合切点:由多个单独的切点共同确定的切点

以上例中流程切点为例,上例中只有一个切点,现对其增加一个切点,使用复合切点。

被代理的类:

package com.pointcut;

/**
 * @author JCL
 * @date 2019-12-11 22:18
 */
public class GreetWaiter {
    public void greeting(){
        System.out.println("welcome to china");
    }


    public void greeting2(String name){
        System.out.println("welcome "+name+" 执行了greeting2方法");
    }


}

复合切点类:

package com.pointcut.composablePointcut;

import com.pointcut.controlFlowPointcut.WaiterDelegate;
import org.springframework.aop.Pointcut;
import org.springframework.aop.support.ComposablePointcut;
import org.springframework.aop.support.ControlFlowPointcut;
import org.springframework.aop.support.NameMatchMethodPointcut;

/**
 * @author JCL
 * @date 2019-12-22 13:25
 */
public class GreetingComposablePointcut {

    //类型返回是Pointcut类型的
    public Pointcut getComposablePointcut(){

    //创建一个复合切点
        ComposablePointcut composablePointcut=new ComposablePointcut();
    //创建一个流程切点
    Pointcut flowPointcut=new ControlFlowPointcut(WaiterDelegate.class,"services");
    //创建一个方法切点
    NameMatchMethodPointcut methodPointcut=new NameMatchMethodPointcut();
    Pointcut pointcut2 =methodPointcut.addMethodName("greeting");
    //intersection是求多个切点的交集,参数必须是Pointcut类,所以必须转以下
   return composablePointcut.intersection(flowPointcut).intersection(pointcut2);
    }

}

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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!--目标类bean-->
    <bean id="greetingWaiter" class="com.pointcut.GreetWaiter"/>
<!--增强类bean-->
    <bean id="beforeAdvice" class="com.pointcut.BeforeAdvice"/>
<!--    复合切点-->
    <bean id="composablePointcut" class="com.pointcut.composablePointcut.GreetingComposablePointcut"/>
<!--    切面-->
<!--    此处是p:pointcut="" 而不是p:pointcut-ref="",引用GreetingComposablePointcut类的getComposablePointcut方法-->
<!--    方法引入时#{....}的形式,若引入的是get方法则需要去除"get"直接写后面的-->
    <bean id="composableAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor"
          p:pointcut="#{composablePointcut.composablePointcut}"
          p:advice-ref="beforeAdvice"/>

    <bean id="waiterGreet" class="org.springframework.aop.framework.ProxyFactoryBean"
          p:interceptorNames="composableAdvisor"
          p:target-ref="greetingWaiter"
          p:proxyTargetClass="true"/> <!--代理目标是否为类-->

</beans>

测试类:

        ClassPathXmlApplicationContext context=
                new ClassPathXmlApplicationContext(new String[]{"composablePointcut.xml"});
        GreetWaiter greetWaiter=(GreetWaiter)context.getBean("waiterGreet");
        WaiterDelegate waiterDelegate=new WaiterDelegate();
        waiterDelegate.setGreetWaiter(greetWaiter);
        waiterDelegate.services("滴滴");

执行结果:

===执行了beforeAdvice增强类方法====
welcome to china
welcome 滴滴 执行了greeting2方法

可以看到,只有执行了greeting方法时才会织入增强类,执行greeting2方法时增强类没被织入。

《五、引质切面》

原理:定义一个接口,然后把接口方法织入到目标类中

目标类:

package com.pointcut.controllablePointcut;

/**
 * @author JCL
 * @date 2019-12-22 22:29
 */
public class Performance {
    public void test1(){
        System.out.println("coming in test1 method");
    }

    public void test2(){
        System.out.println("coming in test2 method");
    }

}

定义接口方法:目的是在目标类中织入接口中方法

package com.pointcut.controllablePointcut;

/**
 * @author JCL
 * @date 2019-12-22 22:22
 */
public interface Monitor {
    void setNeedMonitor(boolean needMonitor);
}

定义引质增强类:

继承: org.springframework.aop.support.DelegatingIntroductionInterceptor类,实现自定义的接口

package com.pointcut.controllablePointcut;

import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.support.DelegatingIntroductionInterceptor;

/**
 * 引质增强类
 * @author JCL
 * @date 2019-12-22 22:21
 */

public class ControllablePerformance extends DelegatingIntroductionInterceptor
                                        implements Monitor{

    private ThreadLocal<Boolean> monitorStatusMap=new ThreadLocal<Boolean>();

    @Override
    public void setNeedMonitor(boolean needMonitor) {
        monitorStatusMap.set(needMonitor);
    }

    //此方法用于拦截目标类的所有方法的调用
    @Override
    public Object invoke(MethodInvocation mi) throws Throwable {
        Object obj=null;
        if (monitorStatusMap.get() !=null && monitorStatusMap.get()) {
            System.out.println("值为true, doSomthing...");


        }
        obj=super.invoke(mi);

        return obj;
    }



}

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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!--目标类bean-->
    <bean id="performanceTarget" class="com.pointcut.controllablePointcut.Performance"/>
<!--增强类bean-->
<!--    <bean id="controllablePerformance" class="com.pointcut.controllablePointcut.ControllablePerformance"/>-->
<!--定义引质切面-->
    <bean id="introductionAdvisor" class="org.springframework.aop.support.DefaultIntroductionAdvisor">
        <constructor-arg>
            <bean class="com.pointcut.controllablePointcut.ControllablePerformance"/>
        </constructor-arg>
    </bean>


    <bean id="performance" class="org.springframework.aop.framework.ProxyFactoryBean"
          p:interceptorNames="introductionAdvisor"
          p:target-ref="performanceTarget"
          p:proxyTargetClass="true"/> <!--代理目标是否为类-->

</beans>

测试类:

    @Test
    public void test24(){
        ClassPathXmlApplicationContext context=
                new ClassPathXmlApplicationContext(new String[]{"introductionPointcut.xml"});
        Performance performance=(Performance)context.getBean("performance");
        performance.test1();
        performance.test2();

        //能强制转换为Monitor说明目标类确实通过引质增强实现类Monitor
        Monitor monitor=(Monitor)performance;
        monitor.setNeedMonitor(true);
        performance.test1();
        performance.test2();

    }

结果输出:

coming in test1 method
coming in test2 method
值为true, doSomthing...
coming in test1 method
值为true, doSomthing...
coming in test2 method

说明引质切面成功了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值