Java——注解开发模式下的 Spring IoC/DI 与 Bean 管理实战

发布于:2025-06-27 ⋅ 阅读:(17) ⋅ 点赞:(0)

在 B 站黑马程序员的 SSM 框架教程中,基于注解的开发模式是简化 Spring 配置、提升开发效率的核心实践。本文结合教程内容,系统解析注解驱动的 IoC(控制反转)、DI(依赖注入)及 Bean 管理,涵盖核心注解、实战技巧与企业级应用场景。

一、IoC 核心:注解声明 Bean 的三种方式

1. 基础注解:@Component 及其衍生注解​

通过注解替代 XML 中的标签,直接在类上声明 Bean,实现 “组件化”:

// 通用组件(推荐细化为专用注解)
@Component("userService") 
public class UserServiceImpl implements UserService { ... }

// 业务层(语义更明确)
@Service("userService") 
public class UserServiceImpl implements UserService { ... }

// 数据访问层(自动参与MyBatis整合)
@Repository("userDao") 
public class UserDaoImpl implements UserDao { ... }

// Web层控制器(自动被SpringMVC扫描)
@Controller("userController") 
public class UserController { ... }

核心规则:​

  • value属性指定 Bean 的 id(可选,默认类名首字母小写)​
  • 需通过<context:component-scan base-package=“com”/>开启组件扫描

2. @Bean:手动定义 Bean(替代 XML 工厂方法)​

在@Configuration类中通过方法返回 Bean,适合第三方组件或复杂对象创建:

@Configuration
public class AppConfig {

    // 配置Druid数据源(替代XML的<bean>)
    @Bean("dataSource")
    public DataSource druidDataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        return dataSource;
    }

    // 整合MyBatis的SqlSessionFactory
    @Bean("sqlSessionFactory")
    public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) {
        SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
        factory.setDataSource(dataSource);
        return factory;
    }
}

适用场景:​

  • 第三方库组件(如 MyBatis、Redis 客户端)​
  • 需要编程式配置的 Bean(动态参数、条件判断)​

3. 条件化 Bean:@Conditional​

根据条件动态注册 Bean(如区分开发 / 生产环境):

// 开发环境启用本地缓存
@Conditional(DevEnvironmentCondition.class) 
@Bean("cacheManager")
public LocalCacheManager devCacheManager() { ... }

// 生产环境启用分布式缓存
@Conditional(ProdEnvironmentCondition.class) 
@Bean("cacheManager")
public RedisCacheManager prodCacheManager() { ... }

二、DI 核心:依赖注入的三种注解方式​

1. 自动装配:@Autowired(byType 为主)​

(1)字段注入(最简洁,但违背 “构造器注入优先” 原则)

@Service
public class UserServiceImpl implements UserService {
    // 自动匹配UserDao类型的Bean(唯一实例)
    @Autowired 
    private UserDao userDao; 
}

(2)构造器注入(推荐有参依赖场景)

@Service
public class UserServiceImpl implements UserService {
    private final UserDao userDao;

    // 单构造器可省略@Autowired(Spring4.3+特性)
    @Autowired 
    public UserServiceImpl(UserDao userDao) { 
        this.userDao = userDao;
    }
}

(3)Setter 方法注入(可选依赖场景)

@Service
public class UserServiceImpl implements UserService {
    private UserDao userDao;

    // 可选依赖:允许userDao为null(需配合@Nullable)
    @Autowired(required = false) 
    public void setUserDao(UserDao userDao) { 
        this.userDao = userDao;
    }
}

2. 精准匹配:@Qualifier 解决歧义​

当同一类型存在多个 Bean 时,通过@Qualifier(“beanId”)指定具体实例:

@Service
public class OrderService {
    // 存在多个DataSource时指定主库
    @Autowired 
    @Qualifier("masterDataSource") 
    private DataSource dataSource; 
}

3. 简单值注入:@Value​

注入基本类型、字符串或 EL 表达式结果:

@Service
public class UserServiceImpl {
    // 注入配置文件中的值
    @Value("${jdbc.username}") 
    private String dbUser; 

    // 注入固定值
    @Value("默认超时时间:3000ms") 
    private String defaultTimeout; 
}

配置支持: 需在 XML 中添加<context:property-placeholder location=“classpath:config.properties”/>

三、Bean 高级特性:生命周期与作用域

1. 生命周期管理注解​

(1)初始化回调:@PostConstruct(替代 XML init-method)

@Service
public class CacheService {
    private Map<String, Object> cache;

    // Bean创建并注入依赖后执行
    @PostConstruct 
    public void init() { 
        cache = new ConcurrentHashMap<>();
    }
}

(2)销毁回调:@PreDestroy(替代 XML destroy-method)

@Service
public class DataSourceService {
    // Bean销毁前释放资源
    @PreDestroy 
    public void close() { 
        // 关闭数据库连接等操作
    }
}

2. 作用域控制:@Scope​

替代 XML 的scope属性,支持 4 种作用域(新增 WebFlux 相关作用域):

// 原型模式:每次注入创建新实例
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) 
@Service("userSession")
public class UserSession { ... }

// Web环境专用(需添加spring-web依赖)
@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS) 
@Service("sessionCache")
public class SessionCache { ... }

**proxyMode:**解决作用域 Bean 注入到单例 Bean 时的生命周期问题(推荐使用 TARGET_CLASS 代理)

3. 延迟初始化:@Lazy​

推迟单例 Bean 的创建(首次使用时初始化):

@Service
@Lazy // 等价于XML的lazy-init="true"
public class HeavyService {
    // 资源密集型Bean延迟加载
}

四、企业级实战:注解与 XML 混合开发

1. 传统 SSM 框架整合(注解为主 + XML 为辅)​

(1)SpringMVC 配置(XML 保留核心组件)

<!-- web.xml -->
<servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:springmvc.xml</param-value>
    </init-param>
</servlet>

<!-- springmvc.xml:保留视图解析器等XML配置 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/views/"/>
    <property name="suffix" value=".jsp"/>
</bean>

<!-- 开启注解驱动:替代XML的<mvc:annotation-driven/> -->
<mvc:annotation-driven/> 

(2)MyBatis 整合(全注解模式)

// 替代XML的MapperScannerConfigurer
@MapperScan("com.dao") // 扫描Mapper接口
@Configuration
public class MyBatisConfig {

    @Bean
    public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) {
        SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
        factory.setDataSource(dataSource);
        factory.setTypeAliasesPackage("com.entity"); // 配置实体类别名
        return factory;
    }
}

2. 复杂场景:多条件 Bean 注册​

通过@Profile实现环境隔离(开发 / 测试 / 生产环境不同配置):

// 开发环境配置
@Profile("dev") 
@Configuration
public class DevConfig {
    @Bean
    public DataSource dataSource() {
        // 配置本地开发数据库
    }
}

// 生产环境配置
@Profile("prod") 
@Configuration
public class ProdConfig {
    @Bean
    public DataSource dataSource() {
        // 配置线上数据库集群
    }
}

**激活方式:**通过 JVM 参数-Dspring.profiles.active=dev或 XML<beans profile="dev">

五、注解开发的优缺点与适用场景​

1. 核心优势​

  • 代码内聚性:Bean 定义与实现逻辑集中在类文件,避免 XML 与代码分离带来的上下文切换​
  • 类型安全:编译期检查依赖匹配错误(如 @Autowired 无匹配 Bean 时编译报错)​
  • 开发效率:消除大量 XML 模板代码,尤其适合快速迭代的互联网项目​

2. 潜在问题​

  • 隐式配置:依赖关系通过注解隐含在代码中,复杂场景下可读性低于 XML​
  • 框架侵入性:业务代码依赖 Spring 注解(如 @Service),增加框架迁移成本​
  • 调试难度:动态代理生成的 Bean 实例,堆栈跟踪时需区分原始类与代理类​

3. 最佳实践​

  • 分层使用:业务层(@Service)、持久层(@Repository)使用注解,基础设施层(数据源、事务管理器)保留 XML 或 @Bean 配置​
  • 组合使用:复杂条件配置用 @Conditional+@Profile,简单 Bean 用 @Component 系列注解​
  • 规范命名:Bean 的 id 统一使用@Component(“xxxService”)显式声明,避免依赖默认命名规则

六、从 XML 到注解:Spring 开发的演进逻辑

特性 XML 配置模式 注解模式
Bean 声明方式 集中式 XML 文件 分散在类文件中(@Component/@Bean
依赖注入方式 显式 隐式
@Autowired+@Qualifier
第三方组件整合 必须 XML 配置 @Bean + 编程式配置
团队协作友好度 配置可见性高(适合新手) 依赖关系隐含(需 IDE 辅助)

黑马教程核心启示: 注解开发的本质是 “约定大于配置”,通过注解简化重复劳动,但需掌握底层原理(如 Spring 如何解析 @Autowired、BeanPostProcessor 如何处理 @PostConstruct)。在企业级开发中,建议采用 “注解为主、XML 为辅” 的混合模式,兼顾效率与可维护性。​

总结:注解时代的 Spring 核心能力​
注解开发模式通过@ComponentScan、@Autowired等核心注解,将 Spring 的 IoC/DI 能力融入代码逻辑,实现 “零 XML” 配置的轻量化开发。掌握这套体系的关键在于:​

  • 精准选择注解:用 @Service/@Repository 明确分层,用 @Bean 处理第三方组件​
  • 理解自动装配规则:区分 byType(@Autowired)与 byName(@Qualifier)的适用场景​
  • 管理 Bean 生命周期:通过 @PostConstruct/@PreDestroy 替代 XML 的 init/destroy 方法​
  • 结合条件与作用域:利用 @Profile/@Scope 实现环境隔离与实例控制

网站公告

今日签到

点亮在社区的每一天
去签到