Spring 纯注解配置全解析(进阶版)

一、纯注解配置核心价值

传统 Spring 开发中大量 XML 配置存在配置繁琐、可读性差、维护成本高的问题,纯注解配置通过 Java 代码替代 XML 文件,实现配置与代码一体化,具备以下优势:

  • 类型安全:编译期即可发现配置错误,而非运行期
  • 灵活性高:可通过 Java 代码实现动态配置逻辑
  • 简洁易维护:配置集中在注解类中,便于团队协作与版本管理

二、核心注解深度解析

1. 配置类核心注解

|-------------------------------|-----------------------------------------------------------|----------------------------------|-------------------------------------------------------------------------------|
| 注解 | 作用 | 替代 XML 标签 | 关键属性 |
| @Configuration | 标记类为 Spring 配置类 | <beans> | 无核心属性,仅作标识 |
| @ComponentScan | 扫描指定包下的组件(@Controller/ @Service/ @Repository/ @Component) | <context: component-scan> | basePackages/value:指定扫描包;excludeFilters:排除指定组件;includeFilters:仅包含指定组件 |
| @PropertySource | 加载外部 properties 配置文件 | <context:property-placeholder> | value:文件路径(类路径需加classpath:);encoding:指定文件编码 |
| @Import | 导入其他配置类,实现配置拆分 | <import resource=""> | value:需导入的配置类字节码数组 |
| @EnableWebMvc | 开启 SpringMVC 注解驱动 | <mvc:annotation-driven> | 无,自动注册 HandlerMapping/HandlerAdapter 等核心组件 |
| @EnableTransaction Management | 开启注解事务支持 | <tx:annotation-driven> | proxyTargetClass:是否使用 CGLIB 代理(默认 false) |

2. Bean 定义核心注解

注解 作用 替代 XML 标签 关键属性
@Bean 方法级别注解,将方法返回对象注册为 Spring Bean <bean> name/value:指定 Bean 名称;initMethod:初始化方法;destroyMethod:销毁方法
@Value 注入配置属性或字面量 <property value=""> 支持 SpEL 表达式(如${jdbc.url}#{T(java.lang.Math).random()}

三、分模块纯注解配置实战

1. 工程结构规划(分层配置)

复制代码
com.hg
├── config          // 配置类目录
│   ├── JdbcConfig.java       // 数据源配置
│   ├── MyBatisConfig.java    // MyBatis配置
│   ├── TxConfig.java         // 事务配置
│   ├── ServiceConfig.java    // 服务层配置
│   ├── SpringMvcConfig.java  // SpringMVC配置
│   ├── SpringConfig.java     // 核心配置(整合所有子配置)
│   └── WebConfig.java        // Web容器配置(替代web.xml)
├── controller      // 控制器层
├── service         // 服务层
├── mapper          // Mapper接口层
├── pojo            // 实体类
├── converter       // 类型转换器
├── interceptor     // 拦截器
└── resources
    └── db.properties  // 数据库配置文件

2. 各模块配置实现(完整可运行版)

(1)数据库配置(JdbcConfig.java)

java 复制代码
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.sql.SQLException;

// 加载数据库配置文件,指定UTF-8编码防止中文乱码
@PropertySource(value = "classpath:db.properties", encoding = "UTF-8")
public class JdbcConfig {

    // 注入配置文件中的属性
    @Value("${jdbc.driver}")
    private String driverClassName;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;
    @Value("${jdbc.maxActive:10}") // 设置默认值,避免配置缺失报错
    private int maxActive;
    @Value("${jdbc.minIdle:5}")
    private int minIdle;

    /**
     * 配置Druid数据源
     * @return 数据源Bean
     */
    @Bean(name = "dataSource", destroyMethod = "close") // 指定销毁方法,释放连接池
    public DataSource dataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(driverClassName);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        // 连接池参数配置
        dataSource.setMaxActive(maxActive);
        dataSource.setMinIdle(minIdle);
        // 可选:配置连接池其他参数
        dataSource.setInitialSize(5);
        dataSource.setMaxWait(60000);
        
        // 开启Druid监控(可选)
        try {
            dataSource.setFilters("stat,wall");
        } catch (SQLException e) {
            throw new RuntimeException("Druid过滤器配置失败", e);
        }
        return dataSource;
    }
}

(2)MyBatis 配置(MyBatisConfig.java)

java 复制代码
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.context.annotation.Bean;

import javax.sql.DataSource;

public class MyBatisConfig {

    /**
     * 配置SqlSessionFactory
     * @param dataSource 自动注入JdbcConfig中配置的数据源
     * @return SqlSessionFactoryBean
     */
    @Bean(name = "sqlSessionFactoryBean")
    public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) {
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        // 设置数据源
        factoryBean.setDataSource(dataSource);
        // 设置实体类别名包(无需在Mapper中写全类名)
        factoryBean.setTypeAliasesPackage("com.hg.pojo");
        // 可选:配置MyBatis全局配置文件
        // factoryBean.setConfigLocation(new ClassPathResource("mybatis-config.xml"));
        // 可选:配置Mapper文件位置(若Mapper接口与XML文件分离)
        // factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml"));
        return factoryBean;
    }

    /**
     * 配置Mapper扫描器,自动生成Mapper代理类
     * @return MapperScannerConfigurer
     */
    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer() {
        MapperScannerConfigurer scannerConfigurer = new MapperScannerConfigurer();
        // 指定Mapper接口所在包
        scannerConfigurer.setBasePackage("com.hg.mapper");
        // 指定SqlSessionFactory名称(与上面的Bean名称对应)
        scannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactoryBean");
        return scannerConfigurer;
    }
}

(3)事务配置(TxConfig.java)

java 复制代码
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;

// 开启事务注解支持
@EnableTransactionManagement
public class TxConfig {

    /**
     * 配置事务管理器
     * @param dataSource 自动注入数据源
     * @return 事务管理器
     */
    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource) {
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(dataSource);
        return transactionManager;
    }
}

(4)服务层配置(ServiceConfig.java)

java 复制代码
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

// 扫描服务层组件,开启AOP代理(可选,若使用AOP)
@ComponentScan("com.hg.service")
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class ServiceConfig {
}

(5)Spring 核心配置(SpringConfig.java)

java 复制代码
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

// 核心配置类,整合所有子配置
@Configuration
@Import({
    JdbcConfig.class,
    MyBatisConfig.class,
    TxConfig.class,
    ServiceConfig.class
})
public class SpringConfig {
}

(6)SpringMVC 配置(SpringMvcConfig.java)

java 复制代码
import com.hg.converter.MyDateConverter;
import com.hg.interceptor.LoginInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

@Configuration
// 扫描控制器、异常处理器等组件
@ComponentScan({"com.hg.controller", "com.hg.exception"})
// 开启SpringMVC注解驱动
@EnableWebMvc
public class SpringMvcConfig implements WebMvcConfigurer {

    /**
     * 注册日期转换器
     */
    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverter(new MyDateConverter());
    }

    /**
     * 配置视图解析器
     */
    @Bean
    public InternalResourceViewResolver viewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/WEB-INF/pages/"); // JSP文件前缀
        resolver.setSuffix(".jsp"); // JSP文件后缀
        resolver.setContentType("text/html;charset=UTF-8"); // 响应编码
        return resolver;
    }

    /**
     * 配置文件上传解析器
     */
    @Bean(name = "multipartResolver") // 名称必须为multipartResolver,否则SpringMVC无法识别
    public CommonsMultipartResolver multipartResolver() {
        CommonsMultipartResolver resolver = new CommonsMultipartResolver();
        resolver.setMaxUploadSize(5 * 1024 * 1024); // 最大上传大小5MB
        resolver.setDefaultEncoding("UTF-8"); // 上传文件编码
        resolver.setMaxInMemorySize(1024 * 1024); // 内存缓存大小
        return resolver;
    }

    /**
     * 配置静态资源映射(放行无需DispatcherServlet处理的资源)
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/head/**") // 访问路径
                .addResourceLocations("/head/"); // 实际文件路径
        // 可添加多个静态资源映射
        // registry.addResourceHandler("/js/**").addResourceLocations("/js/");
    }

    /**
     * 配置拦截器
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())
                .addPathPatterns("/account/**") // 拦截/account下所有请求
                .excludePathPatterns("/user/login", "/user/register"); // 排除登录/注册请求
    }
}

(7)Web 容器配置(WebConfig.java,替代 web.xml)

java 复制代码
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

import javax.servlet.Filter;

/**
 * 替代web.xml的核心类,Servlet3.0+容器会自动检测并初始化
 */
public class WebConfig extends AbstractAnnotationConfigDispatcherServletInitializer {

    /**
     * 配置Spring根容器(非Web层)配置类
     */
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[]{SpringConfig.class};
    }

    /**
     * 配置SpringMVC容器(Web层)配置类
     */
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{SpringMvcConfig.class};
    }

    /**
     * 配置DispatcherServlet的映射路径
     */
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"}; // 拦截所有请求(除静态资源)
    }

    /**
     * 配置过滤器(解决POST请求中文乱码)
     */
    @Override
    protected Filter[] getServletFilters() {
        CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
        encodingFilter.setEncoding("UTF-8");
        encodingFilter.setForceEncoding(true); // 强制所有请求使用指定编码
        return new Filter[]{encodingFilter};
    }
}

3. 简化后的 web.xml

四、关键注意事项

  1. Bean 名称匹配@Bean注解的 name 属性需与依赖注入处的名称一致(如multipartResolver不可改名);
  2. 依赖注入顺序 :通过@Import导入的配置类,Spring 会按数组顺序加载,需保证先加载数据源,再加载 MyBatis / 事务配置;
  3. Servlet 版本要求AbstractAnnotationConfigDispatcherServletInitializer依赖 Servlet3.0+,需保证 web.xml 版本≥3.0 或使用无 web.xml 的纯注解部署;
  4. Druid 数据源销毁 :配置@Bean(destroyMethod = "close")确保容器关闭时释放连接池;
  5. 静态资源放行 :必须通过addResourceHandlers配置,否则 DispatcherServlet 会拦截静态资源请求;
  6. 事务注解生效 :Service 层方法需添加@Transactional,且事务管理器 Bean 名称需为transactionManager(默认匹配)。

五、纯注解配置与 XML 配置对比

功能 XML 配置 注解配置
数据源配置 <bean class="DruidDataSource"> + <property> @Bean + @Value + @PropertySource
组件扫描 <context:component-scan> @ComponentScan
事务管理 <tx:annotation-driven> + <bean class="DataSourceTransactionManager"> @EnableTransactionManagement + @Bean(事务管理器)
SpringMVC 注解驱动 <mvc:annotation-driven> @EnableWebMvc
Web 容器配置 web.xml(监听器 / 过滤器 / Servlet) AbstractAnnotationConfigDispatcherServletInitializer

六、扩展与优化

  1. 配置拆分与复用 :按功能拆分配置类(如 JdbcConfig/MyBatisConfig),通过@Import整合,便于不同环境复用;
  2. 多环境配置 :结合@Profile注解实现开发 / 测试 / 生产环境配置隔离(如@Profile("dev")标注开发环境数据源);
  3. 配置校验 :通过@Validated + JSR303 注解校验配置属性(如@Value("${jdbc.maxActive}") @Min(5) private int maxActive);
  4. 注解属性占位符 :使用@PropertySources(复数)加载多个配置文件,解决@PropertySource单次只能加载一个的问题。

通过以上配置,可完全脱离 XML 文件实现 Spring + SpringMVC + MyBatis 的全注解开发,大幅提升开发效率与配置可维护性。

相关推荐
机器视觉知识推荐、就业指导2 小时前
LVGL真能动摇Qt的地位吗?
开发语言·qt·系统架构
add45a2 小时前
C++代码移植性设计
开发语言·c++·算法
平常心cyk2 小时前
Python基础快速复习——集合和字典
开发语言·数据结构·python
AC赳赳老秦2 小时前
OpenClaw关键词挖掘Agent配置(附SOP脚本,可直接复制使用)
java·大数据·开发语言·人工智能·python·pygame·openclaw
qq_148115372 小时前
分布式系统容错设计
开发语言·c++·算法
leo__5202 小时前
MATLAB高斯背景建模与目标提取(人体检测)
开发语言·人工智能·matlab
m0_560396472 小时前
C++中的享元模式
开发语言·c++·算法
2501_924952692 小时前
分布式缓存一致性
开发语言·c++·算法
茶本无香2 小时前
JDK 21 ZGC分代功能详解:配置、原理及生产环境实践
java·jvm