SpringAOP之切点和切面的深入理解

本文详细介绍了Spring AOP中的切点(pointcut)和切面(advisor),通过实例展示了如何使用StaticMethodMatcherPointcutAdvice、RegexpMethodPointcutAdvisor和DynamicMethodMatcherPointcut进行方法匹配和织入。此外,还探讨了ControlFlowPointcut和IntroductionAdvisor,以及自动代理的实现方式。
摘要由CSDN通过智能技术生成

在看这篇文章之前需要首先理解 Spring AOP 增强的知识,如果你想先了解增强的知识可以移步到 我另外一篇博客《Spring动态代理之详细DEBUG日志模式》里面有关于增强的知识 如果除了增强还有 关于CGlib 和 Proxy 代理的知识不太理解可以再移步到 《动态代理之详细DEBUG日志模式》好了,目前是建基于你都明白 动态代理 和 Spring 增强的基础上进行对Spring 中的 切点(pointcut) 和 切面(advisor)的介绍


如果只有advice 我们一般情况下将一个目标类中的所有方法都进行代理,但是我们希望可以定位的某些类的特定方法,这个时候我们就需要使用到切点(pointcut),然而切面就是切点和增强(advice)的结合。


首先我们通过一个UserService的业务去理解切面和切点的知识,一个有两个方法一个是注册 一个是登录,我们会对这两个方法进行织入演示,所以首先提出这个Service的代码,非常简单的代码:

/**
 * Created by yanzhichao on 27/04/2017.
 */
public class UserService {

    public void login(String username,String password){
        System.out.println("Login : " + username + ", pwd : " + password);
    }

    public void register(String username,String password){
        System.out.println("register : " + username + " , pwd " + password);
    }

}


首先我们先说StaticMethodMatcherPointcutAdvice(这个类名长到我想吐)的使用,主要我们是希望通过这个静态方法匹配切面(原谅我直译)对UserService中的login进行织入。而register不织入:

/**
 * Created by yanzhichao on 27/04/2017.
 */
public class StaticLoginMethodAdvisor extends StaticMethodMatcherPointcutAdvisor {

    //匹配login方法进行织入
    public boolean matches(Method method, Class<?> aClass) {
        return "login".equals(method.getName());
    }

    //定义对什么类有效
    @Override
    public ClassFilter getClassFilter() {
        return new ClassFilter() {
            public boolean matches(Class<?> aClass) {
                //定义对UserService类或者它的派生类有效
                return UserService.class.isAssignableFrom(aClass);
            }
        };
    }
}

然后定义advice 增强,就在方法执行的时候打印一下执行的什么方法的LOG

/**
 * Created by yanzhichao on 27/04/2017.
 */
public class UserAdvice implements MethodBeforeAdvice {

    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println(">>>>>>>>>>" + method.getName() + " invoked !!!");
    }
}

由于我想测试一下advisor中的getClassFilter方法是否有用,所以我再定义了一个AdminService

/**
 * Created by yanzhichao on 27/04/2017.
 */
public class AdminService {

    public void login(String username,String password){
        System.out.println("Admin Login : " + username + ", pwd : " + password);
    }

    public void register(String username,String password){
        System.out.println("Admin register : " + username + " , pwd " + password);
    }

}

同样有login方法,所以再执行两个Service的login方法的时候可以看看输出结果。

最后配置文件的代码如下:

<?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">


    <!-- 未代理的类 -->
    <bean id="userService" class="com.maxfunner.service.impl.UserService" />
    <bean id="adminService" class="com.maxfunner.service.impl.AdminService" />

    <bean id="UserAdvice" class="com.maxfunner.advice.UserAdvice" />

    <bean id="LoginMethodAdvisor" class="com.maxfunner.advisor.StaticLoginMethodAdvisor">
        <property name="advice">
            <bean class="com.maxfunner.advice.UserAdvice" />
        </property>
    </bean>

    <!-- 注意使用了abstract主要是作为一个配置模板去使用,由于我们没有接口实现方式去写Service所以这里使用proxyTargetClass -->
    <bean id="factoryBean" class="org.springframework.aop.framework.ProxyFactoryBean"  abstract="true"
            p:proxyTargetClass="true"
            p:interceptorNames="LoginMethodAdvisor"
    />

    <!-- 定义被proxy bean -->
    <bean id="userServiceProxy" parent="factoryBean" p:target-ref="userService" />
    <bean id="adminServiceProxy" parent="factoryBean" p:target-ref="adminService" />

</beans>

上面注释上已经写的很清楚了,接下来我们使用main方法进行测试一下 然后再贴出一下输出的Log

public static void main(String[] args){
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    UserService userService = (UserService) context.getBean("userServiceProxy");
    AdminService adminService = (AdminService) context.getBean("adminServiceProxy");
    userService.login("TONY","PWD");
    userService.register("TONY","PWD");

    adminService.login("TONY","PWD");
    adminService.register("TONY","PWD");
}

输出可以看到只有userService.login才有被成功增强:

>>>>>>>>>>login invoked !!!
Login : TONY, pwd : PWD
register : TONY , pwd PWD
Admin Login : TONY, pwd : PWD
Admin register : TONY , pwd PWD


但是你会问 既然我们写定义proxy bean的时候就已经定义好那个类进行代理了为什么还有在advisor定义classFilter的方法呢,因为是为了做自动代理,这个留最后说~  接下来我们来做一个更加简单的静态方法切面,通过正则表达式进行限定方法名匹配,这里用到RegexpMethodPointcutAdvisor类,什么都不用改变就该spring配置文件即可:

<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">


    <!-- 未代理的类 -->
    <bean id="userService" class="com.maxfunner.service.impl.UserService" />
    <bean id="adminService" class="com.maxfunner.service.impl.AdminService" />

    <bean id="UserAdvice" class="com.maxfunner.advice.UserAdvice" />


    <!-- pattern是正则表达式,现在我们只针对service包下的所有类的log开头的方法进行织入 -->
    <bean id="LoginMethodAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <property name="patterns">
            <list>
                <value>.*\.service\..*\.log.*</value>
            </list>
        </property>
        <property name="advice">
            <bean 
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值