Spring(一)——Spring介绍与环境搭建、控制反转(IoC)、Spring 属性的注入(依赖注入)、工厂注入(静态和实例、生命周期方法)、Scope(单例 / 多例)、Java代码配置
一、Spring介绍与环境搭建
1、概念
2、Spring架构组成
3、简单理解
4、环境搭建
第一步:
先创建一个 Maven,然后中央仓库搜索 spring-context,选择一个合适的版本,然后在 pom.xml 里面引入依赖:
第二步:
创建 spring配置文件,命名无限制,不过有约定俗成的命名:spring-context.xml、applicationContext.xml、beans.xml。
这里使用 applicationContext.xml 来命名。
注意:必须先引入依赖,才能创建这个文件,如果直接跳过第一步,是不能创建 Spring config 这个文件的。
二、控制反转(IoC)
1、控制反转介绍
项目中强耦合的问题:
解决方案:
2、一个简单的案例
准备好以后接下来就是开始使用:
先随便创建一个实体类:
接着就是注册:
然后就是新建一个测试类,在测试类里面写代码,初始化容器:
怎么验证是否有初始化呢?
在构造方法里随便写一个输出语句,就能发现确实是能够初始化的:
接下来就是在 spring 容器里面要一个对象,然后调用方法:
然后运行就能发现能成功调用方法。
也可以这么调用:
上面的案例中,向 Spring 容器注册一个 Bean,Spring 会通过 Java 的反射机制来创建 UserDao 的一个具体实例,默认情况下,调用的是 UserDao 的无参构造方法。
当然,也可以通过有参构造方法来实现:
3、有参构造方法的注册
有参构造方法需要传递参数,传递方式看下图:
还能根据参数的下标去确定参数:
接着:
4、无参构造方法的注册
有参通过传递参数来注册;同样的,无参也能通过 get 和 set 方法来注册:
三、Spring 属性的注入(依赖注入)
1、p 名称空间注入——本质还是 set 方法注入
2、对象的注入(无参构造方法注入)
创建两个对象:
a、第一种方式——ref 引用
b、第二种方式——直接 Bean 定义(这种方式不能复用对象)
然后测试输出:
3、对象的注入(有参构造方法注入)
方式都差不多,也是直接定义或者 ref 引用
还有一种 p 标签方式:
4、复杂属性的注入
看看其他属性怎么注入,比如数组列表map等等:
其中 cat 的属性是:
a、数组注入
注意:如果数组里面是 String 类型,则用的是 value 标签,使用方式看下面。
b、list 注入
c、set 注入
d、map 注入
e、properties 注入
四、工厂注入
除了上面的注入方式,还有两种注入方式,一种叫静态工厂注入,另外一种叫实例工厂注入。
有的类没有构造方法或者构造方式是私有的,通过一些建造者模式来创建或者使用,这种类如果使用上面得注入方式则会出问题,所以需要使用工厂注入。
为了演示这种问题,先注入一个依赖:okhttp:
这玩意是一个网络请求的工具。
然后就是使用:
返回的结果是 百度 的网页源码。像上图这种创建方式,就不能通过普通的注入来赋予属性了。
那么怎么注入到容器里面去呢?
1、静态工厂方法注入
先写一个类:
然后注入:
接着在测试中写代码时,直接引用就行:
当然,请求还是要写的:
结果就跟前面执行的一样。
2、实例工厂方法注入(推荐方法二)
a、方法一
实例工厂跟静态工厂差不多:
首先方法就不是静态的:
接着就是注入:
然后运行结果还是相同。
b、方法二——实现 FactoryBean 接口(建议使用)
首先需要实现一个接口,并且需要传递一个泛型,限制将来需要返回的对象是谁:
接着实现三个方法:
然后就是注册。这次只需要注册一个 Bean:
然后测试:
结果:
可以发现两个不是同一个对象。
如果设置为 true:
再看结果:
是同一个对象。
获取工厂对象:
如果不想获取那个返回值对象,就是想要获取工厂对象的话,也是可以的:
注意:划红线部分多了个 & 符号。
3、生命周期方法
一般情况下使用的都是初始化方法和销毁方法:
即便是写了这两个方法,默认情况下是不会自动去调用的。需要在配置里面写:
五、Scope(单例 / 多例模式和Web环境下的其他选项)
1、默认情况下为单例模式
提个问题:依赖注入那一块写得例子是单例还是多例的呢?
实验出真知:
随便写个类:
然后注册:
然后代码测试:
结果:
结论:
默认情况下,多次获取该实例,获取的是同一个实例,也说明这个实例默认是单例的。
2、scope——手动设置单例 / 多例模式
看结果:
3、Web 环境下的 scope
如果是 Web 环境下的 scope,则还有三个选项:
request:
session:
application:
六、Java代码配置
1、Java代码代替 xml 配置
前面都是 xml 文件配置,目前都是 java 代码配置的多。
先创建一个实体类:
然后创建一个配置类,作用相当于 xml 文件:
然后跟以前写的一样,里面还要注册属性(依赖注入),这里在对象的上面还要加注解。
接着就是获取容器:
可以看到步骤跟以前一样,这里的这个 ctx 获取的方法跟以前的是一模一样的,因为它们有共同的父类:
然后输出看结果:
2、命名方式
那么问题来了:以前的 bean 标签是有 id 的,id 表明 bean 的名字,如果有多个不会混淆。那么这里的名字怎么表示呢?
默认情况下,方法名就是 bean 的名字,相当于 bean 标签的 id/name 属性。
所以也可以这样写:
还可以通过注解重命名(通过 @Bean 注解中的 name 属性,也可以为 bean 自定义一个名字):
3、scope
默认情况下,这里也是单例的。
如果要使用 scope 调整,则也是通过注解的方式:
4、@Configuration 和 @Component
先来创建两个实体类:
接着注册:
提问:author 和 book 里面的 author 是否是同一个?
测试:
结果:
可以看到是同一个。
这个问题涉及到另外一个注解:@Component
如果使用这个注解:
那么结果将会相反:
在某些版本的 IDEA 下,@Component 注解修饰的配置类,下面可能会有标红(博主的 IDEA 并没有标红):
这个标红不影响运行,但会提醒你现在这种写法有问题,使用的并不是单例,author 会被再次调用一次。如果用回原来的注解,则不会标红。
原因是因为:
@Configuration 有一个拦截功能,当前类中的方法如果调用了当前方法,并不会立马去执行方法, 而是去 Spring 容器中先检查有没有对应的 Bean ,如果有,直接从 Spring 容器中拿回来用,没有才会执行方法。
再来看看第二句话:
建议使用依赖注入代替这个写法:
使用这种写法,容器会自动去查找该方法需要的参数,这样子就不会再标红。