在spring的创建和使用这篇博客中有讲到关于Spring存储和读取Bean对象的操作,但是细心的朋友有没有发现那些操作没有想象中的简单呢?所以呀,我今天要给朋友分享的是更简单的存储和读取Bean对象的方法,快来看看吧~
在Spring中想要更简单的存储和读取对象的核心就是使用注解,这就是我接下来要给朋友讲的啦
讲注解之前,先要在配置文件中添加扫描路径.
目录
想要将对象成功的存储到Spring中,我们需要先配置一下存储对象的扫描包路径,只有被配置了的包下的所有类,添加注解后才能被正确的识别并保存到Spring中.
在 spring-config.xml (此文件为resources目录下自己创建的一个xml文件)中添加如下配置:
这一步很重要,因为即使添加了注解,但如果不是在配置的扫描包下的类对象,仍然是不能被存储到Spring中的.例如上图,只要是在com.zl包下的加了注解的类的对象都可以被存储到Spring中.
若想将Bean对象成功存储到Spring中,有两种类型的注解可以实现:
使用@Controller存储bean的代码如下所示:
读取并使用Bean:
运行APP类,得到一下结果:
以上是五大类注解中@Controller的使用方法,其他四大注解的使用方法与之相同.在这里就不一一演示了.但是现在可能朋友你就要问了,为什么使用方法一样,用一个就好了呀,但是要有这么多类注解呢,接下来我们来看.
为什么要有这么多种类注解,这就和自己的身份证号的前两位一样,比如北京市的身份证号前两位就是11,河北省的前两位是13,湖北省的前两位42等,每个省的身份证号的其两位都不同,这样做的最大的作用就是可以直观的标识这个身份证所处的归属地.
同样这也是为什么需要这么多类注解一样,就是为了方便程序员看到类注解之后,就能直接了解当前类的用途,以下是这些类注解所要传达给程序员的信息:
@Controller:控制类,业务逻辑层,主要验证前端发过来的参数
@Servie:服务类,服务层,数据的处理和接口的调用
@Repository:仓库类,持久层,主要是对数据库的操作,也叫作Dao类
@Configuration:配置类,一些主要负责配置信息的类
@Component:组件类,一些外部实现的工具类
程序的工程分层,调用流程如下:
注:@Component是其他四类类注解的"父类".
类注解是添加在某个类上的,而方法注解是添加到某个方法上的,以下是代码实现:
然后我们在主函数上调用一下bean对象中的user方法,代码如下:
运行一下代码,发现报错,为什么呢?我们来看一下报错信息:
通过报错信息我们可以发现,user找不到,为什么呢,是因为UserController这个类对象没有添加类注解,所以就没有存储到Spring中,所以自然就不能调用这个对象的方法了,所以,我们还要在类上添加一个类注解.
在Spring框架的设计中,方法注解@Bean需要结合类注解才能将对象正常的存储到Spring容器中,如下图代码所示:
我们再来运行一下,得到以下结果:
这样就达到了我们的预期结果.
通过以上例子我们得出一个小小的结论:类注解需要与方法注解搭配使用.
可以通过name属性给Bean对象进行重命名操作,如下代码所示:
然后我们使用user1就可以获取到User对象了,如以下代码所示:
另外,这个重命名的name其实是一个数组,一个bean可以有多个名字,代码如下:
以上写法的话,不论我们是用 user1 还是 user2 都可以获取到User对象了,但是一旦重命名后,就不能写原来的user了.
补充:重命名时,name={}是可以省略的,就像这样:
@Bean("user1") @Bean({"user1","user2"})以上两种重命名的格式都是对的
获取Bean对象也叫装配,是把对象取出来放到某个类中,也叫作对象注入.
对象注入的实现方法有以下3种:
- 属性注入
- 构造方法注入
- Setter注入
下面我将仔细讲解一下这三种注入方式,按照实际开发中的模式,将 Service 类注入到 Controller 类中
属性注入是用 @Autowired 实现的,将 Service 类注入到 Controller 类中.
Service 类的实现代码如下:
Controller 类的实现代码如下:
获取Controller中的getUser方法:
运行结果如下:
属性注入的核心实现为:
属性注入的优缺点分析:
优点: 写法精简,可读性高
缺点: 首先官方就不推荐使用, 专业版 IDAE 会报警告提示.
- 功能方面: 无法注入一个被 final 修饰的对象;容易引起空指针异常
- 通用性方面: 只适用于 IoC 容器
- 设计原则方面: 更加容易违背单一设计原则
无法注入一个被 final 修饰的对象 :
这与java中的语法有关,因为对于被final修饰的对象,只有两种方式对其进行赋值,
- 在声明时直接赋值
- 通过构造方法赋值
容易引起空指针异常:
只适用于 IoC 容器:
属性注入的方式只适用于 IoC 容器, 在非 IoC 框架中使用不了, 可移植性不高, 所以属性注入的通用性不是很好.
更加容易违背单一设计原则:
因为属性注入的写法相对来说较为简单,就容易引起这种注入方式的滥用,所以更容易违背单一性原则.但是并不是说一定会违背,只是有这个可能.
setter注入的核心实现为:
Setter注入优缺点分析:
优点:Setter 注入完全符合单一设计原则, 一个 Setter 方法只针对一个对象.
缺点:
- 不能注入final修饰的对象
- 注入的对象有被修改的风险
不能注入final修饰的对象:
原因和属性注入一样,final修饰的对象要么直接赋值,要么在构造方法中赋值.
注入的对象有被修改的风险:
因为 Setter 注入提供了 setXXX() 方法, 就意味着 setXXX() 可以被调用, 既然能被调用, 则 Setter 注入的对象随时都有被修改的风险.
构造方法注入的核心实现为:
注意:如果只有一个构造方法,则@Autowired可以省略.如果有多个构造方法,则必须在需要注入的构造方法上加入@Autowired表明哪一个是需要被注入的.另外只能注入一个构造方法,因为在普通程序中,我们创建new一个对象时,会根据参数调用其中一个构造方法.
构造方法优缺点分析:
优点:首先它是当前Spring的推荐写法
- 可以注入不可变对象
- 注入的对象不会被修改
- 依赖对象在使用前一定会被完全初始化
- 通用性更好
缺点:写法较为复杂,如果注入对象很多,则代码看起来更臃肿.
可以注入不可变对象:
上面有讲到,被final修饰的属性可以通过构造方法赋值,故在构造方法注入时,可以给final对象赋值
注入的对象不会被修改:
构造方法注入, 在程序执行的时候, 它只会执行一次, 所以不会像 Setter 注入那样被调用多次, 也就不存在被修改的情况.
依赖对象在使用前一定会被完全初始化:
因为我们要注入的对象是在构造方法中实现的,构造方法的执行比类的创建要早, 所以我们要使用的注入的对象, 一定是被完全初始化的.
通用性更好:
构造方法是 JDK 支持的, 往往越底层的框架, 它的可移植性就越好, 所以换做其他任何框架都是适用的.
在进⾏类注⼊时,除了可以使⽤ @Autowired 关键字之外,我们还可以使⽤ @Resource 进⾏注⼊,如 下代码所示:
@Autowired 和 @Resource 的区别:
- 来源不同:@Autowired 来⾃于 Spring,⽽ @Resource 来⾃于 JDK 的注解;
- 使用时设置的参数不同:相⽐于 @Autowired 来说,@Resource ⽀持更多的参数设置,例如 name 设置,根据名称获取 Bean.
- @Autowired 可⽤于 Setter 注⼊、构造函数注⼊和属性注⼊,⽽ @Resource 只能⽤于 Setter 注 ⼊和属性注⼊,不能⽤于构造函数注⼊。
同一类型对应多个Bean时,如何注入自己想要的Bean?
比如当出现以下多个Bean,返回同一对象类型时程序会报错,如下代码所示:
在另一个类中获取User对象,如下:
执行以上程序:
报错原因:非唯一的Bean对象。
那怎么解决呢?有以下两种方法:
对于同一类型多个Bean报错处理:
- 使⽤ @Resource(name="user1") 定义。
- 使⽤ @Qualifier 注解定义名称
1)、使⽤ @Resource(name="user1") 定义:
2)、使⽤ @Qualifier(需要搭配@Autowired)
两者的运行结果都是:
这样问题就解决了~
好啦,到这里就结束啦,回顾一下,五大类注解分别是什么以及他们之间各自起到的标识作用是什么,怎样存储对象、从Spring中获取对象的方式有哪几种,分别怎么获取,这几种方式的优缺点又是什么呢?相信认真看完这篇博客的朋友你应该知道了吧,要是回答不上来,那就再看一下吧
还有,有什么不理解的地方或建议或错误都欢迎指出哦,评论区私信都可~~~