第二篇:告别XML臃肿配置!Spring注解式IOC/DI保姆级教程,从入门到真香

前言

刚学Spring的时候,是不是被一大堆XML配置搞疯了?写一个类就要加一个<bean>标签,依赖多了之后,XML文件动辄几百行,改个配置还要翻半天,维护起来简直是噩梦。

还好Spring早就提供了注解式开发的能力,从Spring 2.5开始支持注解驱动,到现在SpringBoot全注解开发已经成了行业主流,一行XML都不用写,就能玩转IOC和DI。

今天这篇文章,就带大家从零开始,搞定Spring基于注解的IOC和DI,从配置步骤、核心注解,到新手踩坑指南,全给你安排得明明白白,看完就能直接上手,告别XML配置的痛苦!

一、注解式IOC前置准备:一行配置,开启注解新世界

想要用Spring的注解,第一步必须告诉Spring:你要去哪个包里扫描注解。不然你加再多注解,Spring也看不到,根本不会生效!

1. 核心配置:开启包扫描

我们只需要在Spring的application.xml配置文件里,加上这一行配置:

复制代码
配置说明:
  • base-package:指定Spring要扫描的包路径,Spring会扫描这个包,以及它下面所有子包中的类,识别类上的注解。

  • 举个例子:你配置了base-package="com.hg",那么com.hg.daocom.hg.servicecom.hg.controller这些子包,都会被扫描到。

  • 新手踩坑点:90%的新手都踩过这个坑------包路径配错了,比如你的类在com.hg.service里,结果你配成了com.hg.dao,那注解肯定不生效!

2. 包扫描到底做了什么?

Spring启动的时候,会读取这个配置,遍历指定包下的所有class文件,识别出类上添加了IOC相关注解的类,自动把这些类注册成Bean,放到IOC容器里,再也不用我们一个个写<bean>标签了,简直不要太爽!

二、Bean注册四大注解:@Component全家桶,告别<bean>标签

开启包扫描之后,我们只需要在类上加上对应的注解,Spring就会自动把这个类注册成容器里的Bean,不用再写繁琐的XML配置了。

这四个注解,核心功能完全一致------都是把类交给Spring容器管理,只是语义不同,用来区分不同的架构层级,让我们的代码结构更清晰、可读性更高。

1. 四大注解详解

注解 适用场景 核心说明
@Repository Dao层(数据访问层) 标注在数据访问层的实现类上,比如Mapper、Dao实现类
@Service Service层(业务逻辑层) 标注在业务逻辑层的实现类上,用于处理业务逻辑
@Controller Controller层(控制层) 标注在Spring MVC的控制器类上,用于处理前端请求
@Component 三层架构之外的通用组件 通用的组件注解,不属于上面三层的工具类、通用组件,都用这个

2. 代码示例,一看就会

(1)Dao层实现类,添加@Repository注解
复制代码
(2)Service层实现类,添加@Service注解
复制代码

3. 自定义Bean的名称

默认情况下,Spring给Bean生成的名称是类名首字母小写,比如UserServiceImpl对应的beanName是userServiceImpl。

如果你想自定义Bean的名称,直接在注解里指定即可:

复制代码

这样,我们通过getBean("userService"),就能精准拿到这个对象了。

4. 配合@Scope指定Bean的作用域

之前我们讲过Bean的5大作用域,用注解开发的时候,直接用@Scope注解就能指定,无需在XML里配置scope属性。

示例:

复制代码

@Scope里的取值,和XML里的scope属性完全一致,singleton、prototype、request、session、application都可直接使用。

三、依赖注入DI三大注解:告别set方法,一行注解搞定注入

Bean注册到容器里了,那依赖怎么注入呢?比如Service层要注入Dao层的对象,以前我们要在XML里写property属性,还要手写set方法,现在用注解,一行代码就搞定了!

Spring提供了3个核心的DI注解,分别应对不同的注入场景,我们一个个讲透。

1. @Autowired:按类型注入(最常用)

这是我们日常开发中用得最多的注入注解,核心特性是默认按Bean的类型进行依赖注入

用法示例:
复制代码
核心说明:
  • 只要容器里有唯一一个对应类型的Bean,就能自动注入成功,连set方法都不用写,超级方便。

  • 踩坑解决方案:如果容器里有多个同一个类型的Bean,@Autowired会直接报错,因为它不知道该注入哪一个。这时候配合@Qualifier注解,按名称指定要注入的Bean即可:

    复制代码

2. @Resource:按名称注入,也能按类型

这个注解不是Spring提供的,而是JSR-250规范里的官方注解,Spring做了完美支持。它的核心特性是默认按Bean的名称注入,找不到对应名称时,会自动降级按类型注入。

用法示例:
复制代码
面试常问:@Autowired和@Resource的核心区别

这个也是Java面试的高频考点,记住这几个核心差异,面试不翻车:

  1. 来源不同:@Autowired是Spring官方提供的专属注解;@Resource是Java EE的规范注解,来自JSR-250标准。

  2. 注入规则不同:@Autowired默认按类型注入,必须配合@Qualifier才能实现按名称注入;@Resource默认按名称注入,名称匹配不到才会降级按类型注入。

  3. 兼容性不同:@Autowired只有Spring框架支持;@Resource是Java标准规范,所有兼容JSR-250的框架都能支持。

3. @Value:注入基本类型和String

上面两个注解,都是用来注入容器里的Bean对象的,那我们要注入基本数据类型、String类型,甚至配置文件里的配置值,怎么办?用@Value注解就对了!

用法示例:
复制代码

@Value注解非常灵活,不仅能注入固定值,还能读取配置文件、环境变量、系统属性里的内容,日常开发中使用频率极高。

四、注解开发新手必踩的5个坑,避坑指南!

很多同学刚用注解的时候,会遇到各种"注解不生效"、"注入失败报空指针"的问题,90%都是踩了下面这些坑,今天给大家全部列出来,帮大家提前避坑!

坑1:包扫描路径配错了

这是最常见的坑!你的类加了注解,但是Spring的包扫描路径没有包含这个类所在的包,Spring根本扫描不到,注解自然就不生效了。

解决办法:检查context:component-scan的base-package,确保包含了你所有加注解的类的包路径。

坑2:注解加在了接口上,而不是实现类上

很多新手会把@Service、@Repository加在接口上,比如:

复制代码

记住:Spring是给类创建实例、注册Bean的,注解必须加在实现类上,接口上加了等于白加!

坑3:@Autowired注入时,容器里没有对应类型的Bean

比如你要注入UserDao,但是UserDao的实现类没加@Repository注解,容器里根本没有这个类型的Bean,@Autowired就会直接报错。

解决办法:检查要注入的类,有没有添加对应的注解,有没有被Spring的包扫描覆盖到。

坑4:单例Bean注入多例Bean,多例直接失效

这个我们之前也提过,单例Bean只会在容器启动时创建一次,依赖注入也只会执行一次,就算你注入的是多例Bean,也只会注入一次,后续不会自动更新新的实例,导致多例完全失效。

解决办法:可以使用lookup-method注入,或者每次使用时直接从容器中getBean获取,不要直接注入。

坑5:@Autowired注入的对象报空指针异常

很多时候,你明明加了@Autowired,但是运行的时候对象是null,大概率是因为你自己new了这个类的对象,而不是从Spring容器里获取的。

比如你在代码里写了UserService userService = new UserServiceImpl();,这个对象是你自己new出来的,Spring根本管不着,里面的@Autowired自然不会生效,肯定是null。

解决办法:所有要用到的Bean,都从Spring容器里获取,绝对不要自己手动new受Spring管理的类!

总结

看完这篇文章,相信大家已经能感受到Spring注解式开发的香了。对比传统的XML配置,注解开发不仅代码量更少,可读性更高,维护起来也更方便,注解和业务代码放在一起,改起来也不用来回翻XML文件。

今天我们完整讲了:

  1. 注解开发的前置配置:包扫描的配置方式和核心作用;

  2. 注册Bean的四大注解:@Component全家桶的用法、区别和最佳实践;

  3. 依赖注入的三大注解:@Autowired、@Resource、@Value的用法和坑点;

  4. 注解开发新手最容易踩的5个坑,帮大家提前避坑。

现在的企业级开发,不管是传统SSM还是SpringBoot、SpringCloud,基本都是全注解开发,掌握这些注解,是Java开发的必备基本功。

相关推荐
数智化管理手记4 小时前
精益生产中的TPM管理是什么?一文破解设备零故障的密码
服务器·网络·数据库·低代码·制造·源代码管理·精益工程
翊谦4 小时前
Java Agent开发 Milvus 向量数据库安装
java·数据库·milvus
晓晓hh4 小时前
JavaSE学习——迭代器
java·开发语言·学习
Laurence4 小时前
C++ 引入第三方库(一):直接引入源文件
开发语言·c++·第三方库·添加·添加库·添加包·源文件
查古穆5 小时前
栈-有效的括号
java·数据结构·算法
__土块__5 小时前
一次 Spring 事务传播机制源码走读:从误用 @Transactional 到理解嵌套事务的边界
spring·threadlocal·编程式事务·@transactional·事务传播·源码走读·requires_new
kyriewen115 小时前
你点的“刷新”是假刷新?前端路由的瞒天过海术
开发语言·前端·javascript·ecmascript·html5
Java面试题总结5 小时前
Spring - Bean 生命周期
java·spring·rpc
硅基诗人5 小时前
每日一道面试题 10:synchronized 与 ReentrantLock 的核心区别及生产环境如何选型?
java
014-code5 小时前
String.intern() 到底干了什么
java·开发语言·面试