You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AOP切面返回null问题:@Before增强未执行致datap未赋值

问题诊断与解决

嘿,我来帮你分析下为啥你的@Before切面没生效,send()一直返回null。

核心问题:切面与业务类耦合导致代理失效

你把切面逻辑(@Aspect)和业务方法(send())放在了同一个类里,这种情况下Spring不会对这个类生成代理对象——因为Spring会把带有@Aspect的类识别为切面处理器,而不是需要被增强的目标对象。所以当你从容器中拿到data实例调用send()时,根本不会触发my_int_it_method()这个前置增强方法,datap自然一直是null。

除此之外,你的代码还有两个潜在的坑:

  • JDBC资源未关闭:ResultSet、PreparedStatement这些资源用完没关闭,会导致数据库连接泄漏
  • 硬编码初始化Connection:直接在类成员变量里new db_connect()获取连接,不符合Spring的依赖注入思想,也容易引发连接管理问题

修复方案:拆分切面与业务类

最规范的做法是把切面逻辑和业务代码分开,让Spring能正常生成代理对象,触发切面增强。

1. 新建业务类(负责核心逻辑)

把send()方法单独抽出来,作为被增强的目标对象:

package org.main;

public class DataService {
    private String datap;

    // 被切面增强的业务方法
    public String send() {
        return datap;
    }

    public void setDatap(String datap) {
        this.datap = datap;
    }
}

2. 重构切面类(只负责切面逻辑)

把原来的@Aspect代码单独放在一个类里,专注于处理数据库查询和增强逻辑,同时用Spring的方式管理数据库连接:

package org.main;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Aspect
@Component // 让Spring自动扫描并管理这个切面类
public class DataFetchAspect {

    @Autowired
    private Connection dbConnection; // 通过Spring注入数据库连接,替代硬编码

    @Autowired
    private DataService dataService; // 注入业务类,用于设置查询结果

    // 明确指定增强的目标方法:DataService类的send()
    @Before("execution(public String org.main.DataService.send())")
    public void initDatapFromDb() {
        String query = "SELECT type FROM shapes WHERE shape_id=?";
        
        // 使用try-with-resources自动关闭JDBC资源,避免泄漏
        try (PreparedStatement pstmt = dbConnection.prepareStatement(query)) {
            pstmt.setInt(1, 2);
            try (ResultSet rs = pstmt.executeQuery()) {
                if (rs.next()) {
                    dataService.setDatap(rs.getString("type"));
                }
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

3. 更新Spring配置文件

添加组件扫描,让Spring能识别@Component注解,同时配置数据库连接(推荐用数据源而非直接获取Connection):

<?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:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
                           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">

    <!-- 扫描包下的组件,让Spring管理DataService和DataFetchAspect -->
    <context:component-scan base-package="org.main"/>
    
    <!-- 开启AspectJ自动代理 -->
    <aop:aspectj-autoproxy/>

    <!-- 配置数据库数据源(示例用DriverManagerDataSource,生产环境建议用连接池如HikariCP) -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/your_database_name"/>
        <property name="username" value="your_db_user"/>
        <property name="password" value="your_db_password"/>
    </bean>

    <!-- 从数据源获取Connection,供切面类使用 -->
    <bean id="dbConnection" factory-bean="dataSource" factory-method="getConnection"/>
</beans>

4. 修改主执行代码

从容器中获取业务类的代理对象,调用send()方法:

package org.main;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("Spring.xml");
        DataService dataService = ctx.getBean(DataService.class);
        String result = dataService.send();
        System.out.println("查询结果:" + result); // 现在应该能拿到数据库中的type值了
    }
}

验证效果

现在运行Main类,Spring会先执行initDatapFromDb()方法从数据库查询数据,设置到DataService的datap属性中,然后再执行send()方法返回结果,就不会再返回null了。

内容的提问来源于stack exchange,提问作者Jenish Tamrakar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:53:56