说明:Spring的学习是参考江南一点雨的教程(安利这个公众号),教程原文。
Spring
一、Spring简介
Spring是为了解决企业级应用开发的复杂性而创建的。在Spring之前,有一个重量级工具叫做EJB,使用Spring可以让JavaBean之间进行有效的解耦,而这个操作之前只有EJB才能完成,EJB过于臃肿,使用很少。Spring不仅仅局限于服务端的开发,在测试性和松耦合方面都有很好的表现。
二、Ioc
1、Ioc
(1)Ioc概念
Ioc(Inversion of Control),中文叫做控制反转,即对一个对象的控制权的反转。
public class Book{
private Integer id;
private String name;
private Doule price;
...
}
public class User{
private Integer id;
private String name;
private Integer age;
pubic void doSth(){
Book book = new Book();
book.setId(1);
book.setName("故事新编");
book.setPrice((double)20);
}
}
在这种情况下,Book对象的控制权在User对象里面,即Book和User高度耦合,如果在其他对象中需要使用Book对象,得重新创建。也就是说,对象的创建、初始化、销毁等操作,得开发者自己开完成,如果能够将这些操作交给容器来管理,开发者就可以极大的从对象的创建中解脱出来。
使用Spring之后,我们可以将对象的创建、初始化、销毁等操作交给Spring容器来管理。即,在项目启动时,所有的Bean都将自己注册到Spring容器中(如果有必要),然后如果其他Bean需要使用到这个Bean,则不需要自己去new,而是直接去Spring容器要。
(2)实例
在pom.xml中添加spring的依赖:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
</dependencies>
定义Book和User类:
package org.luyangsiyi.test02.bean;
/**
* Created by luyangsiyi on 2020/2/14
*/
public class Book {
private Integer id;
private String name;
private Double price;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
@Override
public String toString() {
return "Book{" +
"id=" + id +
", name='" + name + '\'' +
", price=" + price +
'}';
}
}
package org.luyangsiyi.test02.bean;
/**
* Created by luyangsiyi on 2020/2/14
*/
public class User {
private int id;
private String name;
private String age;
public void doSth(){
Book book = new Book();
book.setId((int)1);
book.setName("故事新编");
book.setPrice((double)20);
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age='" + age + '\'' +
'}';
}
}
配置applicationContext.xml文件(spring相关配置),配置需要注册到Spring容器的Bean,class属性表示需要注册的bean的全路径,id/name则表示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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!--配置所有需要注册到spring容器的bean-->
<bean class="org.luyangsiyi.test02.bean.Book" id="book"/>
</beans>
测试结果:
import org.luyangsiyi.test02.bean.Book;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Created by luyangsiyi on 2020/2/14
*/
public class test {
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
Book book = (Book)ctx.getBean("book");
System.out.println(book);
}
}
2、Bean的获取
一般通过ctx.getBean(Bean的name或id属性)
去获取Bean。
**(不建议)**也可以使用ctx.getBean(Bean.class)
去获取,但是如果存在多个实例,可能会报错。
3、属性的注入
Spring中,如果要将一个Bean注册到Spring容器中,有三种不同的方式:
-
xml注入
-
Java配置
-
自动化扫描
(1)构造方法注入
给Bean添加相应的构造方法:
public class Book{
private Integer id;
private String name;
private Double price;
public Book(iInteger id, String name, Double price){
this.id = id;
this.name = name;
this.price = price;
}
}
在xml中注入Bean,方式一:index:
<bean class="org.luyangsiyi.test02.Book" id="book1">
<constructor-arg index="0" value="1"/>
<constructor-arg index="1" value="三国演义"/>
<constructor-arg index="2" value="30"/>
</bean>
方法二:name:
<bean class="org.luyangsiyi.test02.Book" id="book2">
<constructor-arg name="id" value="2"/>
<constructor-arg name="name" value="红楼梦"/>
<constructor-arg name="price" value="30"/>
</bean>
(2)set方法注入
<bean class="org.luyangsiyi.test02.Book" id="book3">
<property name="id" value="3"/>
<property name="name" value="水浒传"/>
<property name="price" value="3"/>
</bean>
set方法的注入需要注意属性名并不是你定义的属性名,而是通过Java中的内省机制分析出来的属性名,即get/set方法分析出来的属性名。
(3)p名称空间注入
使用的较少。
<bean class="org.luyangsiyi.test02.Book" id="book4" p:id="4" p:bookName="西游记" p:price="30"></bean>
(4)外部Bean的注入
① 静态工厂方法
public class BookFactory{
public static Book buyBook(){
Book book = new Book();
book.setName("java");
return book;
}
}
<bean id="book" class="...BookFactory" factory-method="buyBook"></bean>
② 非静态工厂方法
必须实例化工厂类之后才能调用工厂方法。
public class BookFactory{
public Book buyBook(){
Book book = new Book();
book.setName("java");
return book;
}
}
<bean id="bookFactory" class="...bean.BookFactory"></bean>
<bean id="book" factory-bean="bookFactory" factory-method="buyBook"></bean>
因为bookFactory的工厂方法不是静态的,因此需要定义一个工厂类的bean,然后通过factory-bean属性来引用工厂bean实例,通过factory-method属性来指定对应的工厂方法。
4、复杂属性的注入
(1)对象注入
<bean class="org.luyangsiyi.test02.User" id="user">
<property name="cat" ref="cat"/>
</bean>
<bean class="org.luyangsiyi.test02.Cat" id="cat">
<property name="name" value="小白"/>
<property name="color" value="白色"/>
</bean>
可以通过xml注入对象,通过ref来引用一个对象。
(2)数组/集合注入
<bean class="org.luyangsiyi.test02.User" id="user">
<property name="cat" ref="cat"/>
<property name="favorites">
<array>
<value>足球</value>
<value>篮球</value>
<value>乒乓球</value>
</array>
</property>
</bean>
<bean class="org.luyangsiyi.test02.Cat" id="cat">
<property name="name" value="小白"/>
<property name="color" value="白色"/>
</bean>
注意,array节点也可以被list节点替代。array/list节点中也可以是对象,即可以通过ref使用外部定义好的Bean,也可以直接在其中定义。