Spring-AOP更加细化的织入时机

本文详细介绍了Spring AOP中如何通过PointcutAdvisor和Introduction实现特定方法前的用户验证,包括使用NameMatchMethodPointcutAdvisor和RegexpMethodPointcutAdvisor来精确匹配方法名,以及如何通过Introduction为对象动态添加验证行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在上文 Spring学习:AOP思想中已经介绍了,AOP思想,以及springAOP的初步使用方法。在上文中,所介绍到的MethodBeforeAdvice是为代理对象的每个方法执行前执行用户验证。那么现在就有一个问题,如果只是business1()和business2()执行前需要用户验证,我们应该怎么做?下面来介绍。

细化的SpringAOP织如时机

回顾一下上次的内容,有一个component类继承了Icomponent接口,并实现了接口的三个业务逻辑business1(),business2(),business3()我们希望在每个方法执行前调用用户验证。

//Icomponent接口
package com.cst.spring.lab3;

public interface Icomponent {

    public void business1();
    public void business2();
    public void business3();
}

//component类
package com.cst.spring.lab3;

/**
 * @author Cst
 *
 */
public class Component implements Icomponent{

    public void business1()
    {
        System.out.println("业务1");
    }

    public void business2()
    {
        System.out.println("业务2");
    }
    public void business3()
    {
        System.out.println("业务3");
    }

}

我们可以通过实现MethodBeforeAdvice接口来实现所需要的要求,详看上文。
那么现在我们只需要为business1()执行前执行用户验证,怎么做?

Spring内建的Pointcut都有对应的PointcutAdvisor,
使用org.springframework.aop.support.NameMatchMethodPointcutAdvisor提供静态的Pointcut实例,使用表达式指定Advice应用目标上的方法名称,或者用*来指定。

1.实现MethodBeforeAdvice接口实现ValidateBeforeMethod类

public class ValidateBeforeMethod implements MethodBeforeAdvice{

    public void before(Method arg0, Object[] arg1, Object arg2)
            throws Throwable {
        // TODO Auto-generated method stub
        this.validate();
        System.out.println(arg0);

    }

    public void validate()
    {
        System.out.println("验证用户");
    }
}

2.配置xml

<!-- 定义component-->
<bean id="component" class="com.cst.spring.lab3.Component"/>

<!--为busines1,2添加MethodBeforeAdvice-->
<bean id="componentadvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
        <!-- 为希望的方法添加advice -->
        <property name="mappedName" value="*business1"/>
        <!-- 添加的advice -->
        <property name="advice" ref="validatebeforeadvice"/>
    </bean>

<!--为component绑定Advisor-->
<bean id="componentproxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="proxyInterfaces" value="com.cst.spring.lab3.Icomponent"/>
        <property name="target" ref="component"/>
        <property name="interceptorNames">
            <list>
                <value>componentadvisor</value>
            </list>
        </property>
    </bean>

3.测试类

public class AopExample {

    public static void main(String[] args) {

        ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
        Icomponent icom=(Icomponent)context.getBean("componentproxy");
        icom.business1();
    }

}

如果需要为busines1()和business2()又如何做?

Spring 提供org.springframework.aop.support.RegexpMethodPointcutAdvisor
使用正则表达式来编写Pointcut表达式,其值为“pattern”属性值。

<!--为busines1,2添加MethodBeforeAdvice-->
    <bean id="componentadvice" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <!-- 使用正则表达式为希望的方法添加advice -->
        <property name="pattern" value=".*business(1|2)"/>
        <!-- 添加的advice -->
        <property name="advice" ref="validatebeforeadvice"/>
    </bean>

Introduction

在Spring中,Introduction是一种特殊的Advice,直接介入整个对象的行为,好像对象凭空多了可操作的行为,为对象动态加入原先所没有的职责。

可以通过实现org.springframework.aop.IntroductionInterceptor来实现Introduction

在不修改原始文件的情况下,
将增加的可操作方法放在另一接口中将Introduction织入到目标对象上,使用org.springframework.aop.support.DefaultIntroductionAdvisor

也就是说我们可以将用户验证方法使用Introduction织入到目标对象中。实现如下

1.定义用户验证接口类


public interface IValidate {

    public void Validate();
}

2.实现Introduction


//实现了接口Ivalidate与IntroductionInterceptor
public class ValidateIntroduction implements IValidate, IntroductionInterceptor {

    public Object invoke(MethodInvocation arg0) throws Throwable {
        if(implementsInterface(arg0.getMethod().getDeclaringClass()))
        {
            return arg0.getMethod().invoke(this, arg0.getArguments());
        }
        else
        {
            return arg0.proceed();
        }
    }

    //判断是否继承验证接口
    public boolean implementsInterface(Class arg0) {

        return arg0.isAssignableFrom(IValidate.class);
    }

    public void Validate() {
        System.out.println("用户验证");
    }

}

3.配置xml文件

<!-- componentbean -->
<bean id="component" class="com.cst.spring.lab3.Component"/>

<!-- introduction -->
    <bean id="validateintroduction" class="com.cst.spring.lab3.ValidateIntroduction"/>


<!-- Advisor -->
<bean id="validateAdvisor" class="org.springframework.aop.support.DefaultIntroductionAdvisor">
        <constructor-arg ref="validateintroduction"/>
        <constructor-arg value="com.cst.spring.lab3.IValidate"/>
    </bean>

<!-- 绑定到目标对象 -->
<bean id="componentproxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="proxyInterfaces" value="com.cst.spring.lab3.Icomponent"/>
        <property name="target" ref="component"/>
        <property name="interceptorNames">
            <list>
                <value>validateAdvisor</value>
            </list>
        </property>
    </bean>

4.测试类

public class AopExample {

    public static void main(String[] args) {
        ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
        Icomponent icom=(Icomponent)context.getBean("component");


        ((IValidate)icom).Validate();
        icom.business1();
        ((IValidate)icom).Validate();
        icom.business2();

    }

}

以上便实现了使用Introduction在business1(),business2()前进行用户验证。

自动代理Autoproxing

利用BeanNameAutoProxyCreator完成自动代理。

<!-- componentbean -->
<bean id="component" class="com.cst.spring.lab3.Component"/>

<!-- introduction -->
    <bean id="validateintroduction" class="com.cst.spring.lab3.ValidateIntroduction"/>

<!-- Advisor -->

    <bean id="validateAdvisor" class="org.springframework.aop.support.DefaultIntroductionAdvisor">
        <constructor-arg ref="validateintroduction"/>
        <constructor-arg value="com.cst.spring.lab3.IValidate"/>
    </bean>

<!-- 利用BeanNameAutoProxyCreator完成自动代理 -->
    <bean id="introductionproxycreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
    <!-- 代理目标 -->
        <property name="beanNames">
            <list>
                <value>component</value>
            </list>
        </property>
        <!-- Advisor -->
        <property name="interceptorNames" value="validateAdvisor"/>
    </bean>

测试类如上。

以上便是本文的全部内容。有错误请指出,谢谢

### Spring Boot 中常用注解及其详细说明 #### 1. 核心注解 Spring Boot 提供了一些核心注解,用于简化配置并提高开发效率。以下是几个重要的核心注解: - **`@SpringBootApplication`**: 这是一个复合注解,包含了 `@SpringBootConfiguration`, `@EnableAutoConfiguration`, 和 `@ComponentScan` 的功能[^2]。它通常被放置在应用程序的主类上,作为整个项目的启动口。 - **`@SpringBootConfiguration`**: 表明当前类是一个配置类,并且可以与其他 Spring Boot 特定的功能配合使用[^3]。 - **`@EnableAutoConfiguration`**: 启用 Spring Boot 自动配置机制,根据 classpath 上存在的依赖项自动生成相应的 Bean 定义。 - **`@ComponentScan`**: 扫描指定包下的组件(如 Controller、Service、Repository),并将它们注册为 Spring 容器中的 Bean。 --- #### 2. 数据验证注解 为了确保数据的有效性和一致性,Spring Boot 支持多种内置的数据验证注解: - **`@NotNull`**: 被标注的字段不能为空对象[^4]。 - **`@NotEmpty`**: 字符串、集合、数组等类型的值既不能为 null,也不能为空(即 isEmpty 方法返回 false)。适用于 String、Collection、Map 等类型。 - **`@NotBlank`**: 主要针对字符串类型,不仅要求非空,还要求去掉前后空白字符后长度大于零。 - **`@Size(min=, max=)`**: 指定字段的大小范围,支持字符串长度、集合元素数量以及数组长度的校验。 --- #### 3. 控制层相关注解 控制层注解主要用于定义 RESTful API 或传统 MVC 请求处理逻辑: - **`@RestController`**: 将控制器标记为专门用于响应 JSON/XML 数据的 RestController 类型,省去了手动设置 `@ResponseBody` 的麻烦[^1]。 - **`@RequestMapping`**: 映射 HTTP 请求到特定的方法或类上,可以通过路径、请求方式等多种属性进行细化配置。 - **`@GetMapping`, `@PostMapping`, `@PutMapping`, `@DeleteMapping`**: 分别对应 GET、POST、PUT 和 DELETE 请求方法的快捷映射形式。 --- #### 4. 配置管理注解 这些注解帮助开发者更方便地加载外部配置文件或将环境变量注程序内部: - **`@Value("${property.key}")`**: 从 properties 文件或其他配置源中读取键对应的值,并将其赋给某个字段或参数。 - **`@PropertySource("classpath:config.properties")`**: 加载额外的 property 文件至 Environment 对象中以便后续访问。 - **`@ConfigurationProperties(prefix="app.config")`**: 绑定一组具有相同前缀的配置项到 JavaBean 属性里,便于集中管理和维护复杂结构化数据。 --- #### 5. 测试专用注解 测试阶段经常需要用到的一些辅助工具类注解如下所示: - **`@SpringBootTest`**: 初始化完整的 ApplicationContext 实例来进行集成测试操作。 - **`@MockBean`**, **`@SpyBean`**: 创建模拟对象替代真实服务实例参与单元/集成测试流程,前者完全伪造行为模式而后者则部分保留原生实现细节。 --- #### 6. AOP 切面编程相关注解 面向切面编程 (AOP) 可以让业务逻辑更加清晰分离出来: - **`@Aspect`**: 定义一个切面类,在其中编写横切关注点的具体实现代码。 - **`@Before`, `@After`, `@Around`, etc.**: 描述不同执行时机下切目标方法的行为特征,比如前置增强、后置增强等等。 --- ```java // 示例:如何在一个简单的 Spring Boot 应用中使用 @SpringBootApplication 注解 @SpringBootApplication public class MyApplication { public static void main(String[] args) { SpringApplication.run(MyApplication.class, args); } } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值