Spring-学习笔记
Posted 程序航
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring-学习笔记相关的知识,希望对你有一定的参考价值。
官网
Spring组件
Spring 中的组件,大致上提供了如下功能:
IOC
概念
Ioc (Inversion of Control),中文叫做控制反转。这是一个概念,也是一种思想。控制反转,实际上就是指对一个对象的控制权的反转。
Ioc介绍
首先创建一个普通的 Maven 项目,然后引入 spring-context 依赖,如下:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
</dependencies>
接下来,在 resources 目录下创建一个 spring 的配置文件(注意,一定要先添加依赖,后创建配置文件,否则创建配置文件时,没有模板选项):
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
在这个文件中,我们可以配置所有需要注册到 Spring 容器的 Bean:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="org.javaboy.Book" id="book"/>
</beans>
class 属性表示需要注册的 bean 的全路径,id 则表示 bean 的唯一标记,也开可以 name 属性作为 bean 的标记,在超过 99% 的情况下,id 和 name 其实是一样的,特殊情况下不一样。
接下来,加载这个配置文件:
public class Main {
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
}
}
执行 main 方法,配置文件就会被自动加载,进而在 Spring 中初始化一个 Book 实例。此时,我们显式的指定 Book 类的无参构造方法,并在无参构造方法中打印日志,可以看到无参构造方法执行了,进而证明对象已经在 Spring 容器中初始化了。
最后,通过 getBean 方法,可以从容器中去获取对象:
public class Main {
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
Book book = (Book) ctx.getBean("book");
System.out.println(book);
}
}
加载方式,除了ClassPathXmlApplicationContext 之外(去 classpath 下查找配置文件),另外也可以使用 FileSystemXmlApplicationContext ,FileSystemXmlApplicationContext 会从操作系统路径下去寻找配置文件。
public class Main {
public static void main(String[] args) {
FileSystemXmlApplicationContext ctx = new FileSystemXmlApplicationContext("F:\\\\workspace5\\\\workspace\\\\spring\\\\spring-ioc\\\\src\\\\main\\\\resources\\\\applicationContext.xml");
Book book = (Book) ctx.getBean("book");
System.out.println(book);
}
}
通过 Class获取Bean
public class Main {
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
Book book = ctx.getBean(Book.class);
System.out.println(book);
}
}
这种方式有一个很大的弊端,如果存在多个实例,这种方式就不可用,例如,xml 文件中存在两个 Bean:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="org.javaboy.Book" id="book"/>
<bean class="org.javaboy.Book" id="book2"/>
</beans>
此时,如果通过 Class 去查找 Bean,会报如下错误:
所以,一般建议使用 name 或者 id 去获取 Bean 的实例。
属性注入
构造方法注入
通过 Bean 的构造方法给 Bean 的属性注入值。
- 第一步首先给 Bean 添加对应的构造方法:
public class Book implements Serializable {
private static final long serialVersionUID = 5492270562431552420L;
private Integer id;
private String name;
private Double price;
public Book() {
}
public Book(Integer id, String name, Double price) {
this.id = id;
this.name = name;
this.price = price;
}
}
- 在 xml 文件中注入 Bean
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--构造方法注入:不能清晰看到定义的哪个属性,不推荐使用-->
<bean id="book" class="cn.sail.training.spring.ioc.Book">
<constructor-arg index="0" value="1"/>
<constructor-arg index="1" value="红楼梦"/>
<constructor-arg index="2" value="33"/>
</bean>
</beans>
constructor-arg 中的 index 和 Book 中的构造方法参数一一对应。写的顺序可以颠倒,但是 index 的值和 value 要一一对应。
另一种构造方法中的属性注入,则是通过直接指定参数名来注入:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--构造方法注入:参数名指定,可以较直观的看到定义的属性,推荐使用-->
<bean id="book1" class="cn.sail.training.spring.ioc.Book">
<constructor-arg name="id" value="2"/>
<constructor-arg name="name" value="西游记"/>
<constructor-arg name="price" value="40"/>
</bean>
</beans>
如果有多个构造方法,则会根据给出参数个数以及参数类型,自动匹配到对应的构造方法上,进而初始化一个对象。
set 方法注入
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--set方法注入:可以较直观的看到定义的属性,推荐使用-->
<bean id="user" class="cn.sail.training.spring.ioc.User">
<property name="id" value="1"/>
<property name="age" value="27"/>
<property name="name" value="廖航"/>
</bean>
</beans>
set 方法注入,不是根据属性名对应的值,而是根据 get/set 方法分析出来的属性名。
如果改变set方法的名称,就算属性名不变,也会找不到值而报错。
p 名称空间注入
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--p名称空间注入:本质上也是调用了set方法,层次结构不清晰,且需要额外引进标签值,不推荐使用-->
<bean id="book2" class="cn.sail.training.spring.ioc.Book" p:id="2" p:name="西游记" p:price="33"/>
</beans>
静态工厂注入
首先提供一个 OkHttpClient 的静态工厂:
import okhttp3.OkHttpClient;
public class OkHttpUtils {
private static OkHttpClient okHttpClient;
public static OkHttpClient getInstance() {
if (okHttpClient == null) {
okHttpClient = new OkHttpClient.Builder().build();
}
return okHttpClient;
}
}
在 xml 文件中,配置该静态工厂:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--静态工厂注入-->
<bean id="okHttpUtils" class="cn.sail.training.spring.ioc.OkHttpUtils" factory-method="getInstance"/>
</beans>
这个配置表示 OkHttpUtils 类中的 getInstance 是我们需要的实例,实例的名字就叫 okHttpClient。然后,在 Java 代码中,获取到这个实例,就可以直接使用了。
实例工厂注入
实例工厂就是工厂方法是一个实例方法,这样,工厂类必须实例化之后才可以调用工厂方法。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--实例工厂注入-->
<bean id="okHttpUtils" class="cn.sail.training.spring.ioc.OkHttpUtils" factory-method="getInstance"/>
<bean id="okHttpClient1" class="okhttp3.OkHttpClient" factory-bean="okHttpUtils"/>
</beans>
复杂属性注入
对象注入
可以通过 xml 注入对象,通过 ref 来引用一个对象。
<bean id="user1" class="cn.sail.training.spring.ioc.User">
<property name="cat" ref="cat"/>
</bean>
<bean id="cat" class="cn.sail.training.spring.ioc.Cat">
<property name="name" value="小白"/>
<property name="color" value="白色"/>
</bean>
数组注入
<bean id="user2" class="cn.sail.training.spring.ioc.User">
<property name="favorites">
<array>
<value>足球</value>
<value>篮球</value>
<value>乒乓球</value>
</array>
</property>
</bean>
集合注入
即可以通过 ref 使用外部定义好的 Bean,也可以直接在 list 或者 array 节点中定义 bean。
<bean id="user3" class="cn.sail.training.spring.ioc.User">
<property name="cats">
<list>
<ref bean="cat"/>
<bean id="cat2" class="cn.sail.training.spring.ioc.Cat">
<property name="name" value="小黑"/>
<property name="color" value="黑色"/>
</bean>
</list>
</property>
</bean>
Map注入
<bean id="user4" class="cn.sail.training.spring.ioc.User">
<property name="map">
<map>
<entry key="name" value="sail"/>
<entry key="age" value="27"/>
</map>
</property>
</bean>
Properties注入
<bean id="user5" class="cn.sail.training.spring.ioc.User">
<property name="info">
<props>
<prop key="name">sail</prop>
<prop key="age">27</prop>
</props>
</property>
</bean>
Java配置
在 Spring 中,想要将一个 Bean 注册到 Spring 容器中,整体上来说,有三种不同的方式。
- XML 注入
- Java 配置(通过 Java 代码将 Bean 注册到 Spring 容器中)
- 自动化扫描
Java配置的方式注册有以下步骤:
-
配置类上加@Configuration注解,这个注解表示这个类不是一个普通类,而是一个配置类,它的作用相当于 applicationContext.xml
-
定义方法,方法返回对象,方法上添加@Bean注解,表示将这个方法的返回值注入的Spring容器中去。也就是说,@Bean所对应的方法,就相当于applicationContext.xml中的bean节点。
@Configuration
public class Config {
@Bean
User user() {
return new User();
}
}
配置加载
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Config.class);
User user = ctx.getBean(User.class);
Bean的默认名称是方法名。如果想自定义方法名,直接在@Bean中进行配置。如下配置表示修改Bean的名字为sail:
@Configuration
public class Config {
@Bean("sail")
User user() {
return new User();
}
}
配置加载
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Config.class);
User user = ctx.getBean("sail", User.class);
注:配置类需要在项目启动时加载才生效。
以上是关于Spring-学习笔记的主要内容,如果未能解决你的问题,请参考以下文章