Spring Ioc是Spring公司对“控制反转”思想的实现,运用xml来管理和创建bean
三种XML管理、创建bean的方式:
-
基于构造方法实例对象。
-
基于静态工厂实例化对象。
-
基于工厂实例方法实例化对象。
实体类
package pers.thc.spring.IoC.entity;
public class Apple {
private String title;
private String color;
private String origin;
public Apple(){}
public Apple(String title, String color, String origin) {
this.title = title;
this.color = color;
this.origin = origin;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public String getOrigin() {
return origin;
}
public void setOrigin(String origin) {
this.origin = origin;
}
@Override
public String toString() {
return "Apple{" +
"title='" + title + '\'' +
", color='" + color + '\'' +
", origin='" + origin + '\'' +
'}';
}
}
package pers.thc.spring.IoC.entity;
public class Child {
private String name;
private Apple apple;
public Child(){}
public Child(String name, Apple apple) {
this.name = name;
this.apple = apple;
}
@Override
public String toString() {
return "Child{" +
"name='" + name + '\'' +
", apple=" + apple +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Apple getApple() {
return apple;
}
public void setApple(Apple apple) {
this.apple = apple;
}
}
静态工厂类
package pers.thc.spring.IoC.factory;
import pers.thc.spring.IoC.entity.Apple;
public class AppleFactory {
public static Apple createSweetApple(){
Apple apple = new Apple("红富士", "深红", "欧洲");
return apple;
}
}
实例工厂类
package pers.thc.spring.IoC.factory;
import pers.thc.spring.IoC.entity.Apple;
public class AppleFactoryInstance {
public Apple createSweetApple(){
Apple apple = new Apple("红富士", "深红", "欧洲");
return apple;
}
}
applicationContext.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="sweetApple" class="pers.thc.spring.IoC.entity.Apple">
<property name="title" value="红富士"/>
<property name="color" value="深红"/>
<property name="origin" value="欧洲"/>
</bean>
<bean id="sourApple" class="pers.thc.spring.IoC.entity.Apple">
<property name="origin" value="中亚"/>
<property name="color" value="青色"/>
<property name="title" value="青苹果"/>
</bean>
<bean id="softApple" class="pers.thc.spring.IoC.entity.Apple">
<property name="title" value="金帅"/>
<property name="color" value="金色"/>
<property name="origin" value="中国"/>
</bean>
<bean class="pers.thc.spring.IoC.entity.Apple">
<property name="title" value="苹果"/>
<property name="color" value="未知"/>
<property name="origin" value="位置"/>
</bean>
<bean name="Lily,lily" class="pers.thc.spring.IoC.entity.Child">
<property name="apple" ref="sweetApple"/>
<property name="name" value="Lily"/>
</bean>
<bean id="apple1" class="pers.thc.spring.IoC.entity.Apple">
<constructor-arg name="title" value="红富士"/>
<constructor-arg name="color" value="深红"/>
<constructor-arg name="origin" value="欧洲"/>
</bean>
<bean id="apple2" class="pers.thc.spring.IoC.entity.Apple">
<constructor-arg index="0" value="红富士"/>
<constructor-arg index="1" value="深红"/>
<constructor-arg index="2" value="欧洲"/>
</bean>
<!--采用静态工厂的形式创建apple实例-->
<bean id="apple3" class="pers.thc.spring.IoC.factory.AppleFactory" factory-method="createSweetApple"/>
<!--采用工厂实例的形式创建apple实例-->
<bean id="appleFactoryInstance" class="pers.thc.spring.IoC.factory.AppleFactoryInstance"/>
<bean id="apple4" factory-bean="appleFactoryInstance" factory-method="createSweetApple"/>
</beans>
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="sweetApple" class="pers.thc.spring.IoC.entity.Apple">
<property name="title" value="富士"/>
<property name="color" value="深红"/>
<property name="origin" value="日本"/>
</bean>
</beans>
Application类
package pers.thc.spring.IoC;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import pers.thc.spring.IoC.entity.Apple;
import pers.thc.spring.IoC.entity.Child;
public class SpringApplication {
public static void main(String[] args) {
String configLocations[]=new String[]{
"classpath:applicationContext.xml", "classpath:applicationContext1.xml"};
//应用上下文加载顺序与字符串先后顺序有关
//启动IoC容器
// ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(configLocations);
//利用getBean来获取相应的实例对象
// Apple sweetApple = (Apple)context.getBean("sweetApple");
Apple sweetApple = context.getBean("sweetApple", Apple.class);//由于sweetApple在两个配置文件中都有,故后加载的配置文件中的sweetApple会覆盖掉先加载配置文件中的sweetApple
Child Lily = context.getBean("Lily", Child.class);
Child lily = context.getBean("lily", Child.class);//通过name标签可以设置多个bean标识,此处用lily标识获取实例对象
Apple apple = context.getBean("pers.thc.spring.IoC.entity.Apple", Apple.class);//若bean没有id、name标签,则通过完整类名获取实例对象
Apple apple1 = context.getBean("apple1", Apple.class);
Apple apple2 = context.getBean("apple2", Apple.class);
Apple apple3 = context.getBean("apple3", Apple.class);
Apple apple4 = context.getBean("apple4", Apple.class);
System.out.println(sweetApple);
System.out.println(Lily);
System.out.println(lily);
System.out.println(apple);
System.out.println(apple1);
System.out.println(apple2);
System.out.println(apple3);
System.out.println(apple4);
}
}
路径表达式:
-
classpath:config.xml 扫描classpath根路径(不包含jar)的config.xml
-
classpath:pers/thc/config.xml 扫描classpath下(不包含jar)pers.thc包中的config.xml
-
classpath*:pers/thc/config.xml 扫描classpath下(包含jar)pers.thc包中的config.xml
-
classpath:config-*.xml 扫描classpath根路径下所有一config-开头的XML文件
-
classpath:pers/**/config.xml 扫描pers包下(包含任何子包)的config.xml file:c/:config.xml 扫描c盘根路径config.xml
两种对象依赖注入方式:
-
setter注入对象(property)
-
构造方法注入对象(constructor-arg)
IoC模拟团队分工:
bookshop 利用不同的配置文件,约定好bean的id,建立依赖关系(service的parent context为dao),实现分工合作。 其次,利用IoC容器还可以实现对象之间的解耦,当dao层修改实现细节时,秩序保证bean的id不变,service层不需要进行任何改变。
注入集合对象:
通过“公司资产配置清单”案例学习集合类型动态注入
公司实体类
package pers.thc.spring.IoC.companyProperties.entity;
import java.util.List;
import java.util.Map;
import java.util.Properties;
public class Company {
private List<String> rooms;
private Map<String,Computer> computers;
private Properties info;
@Override
public String toString() {
return "Company{" +
"rooms=" + rooms +
", computers=" + computers +
", info=" + info +
'}';
}
public List<String> getRooms() {
return rooms;
}
public void setRooms(List<String> rooms) {
this.rooms = rooms;
}
public Map<String, Computer> getComputers() {
return computers;
}
public void setComputers(Map<String, Computer> computers) {
this.computers = computers;
}
public Properties getInfo() {
return info;
}
public void setInfo(Properties info) {
this.info = info;
}
}
电脑实体类
package pers.thc.spring.IoC.companyProperties.entity;
public class Computer {
private String brand;
private String type;
private String sn;
private Float price;
public Computer() {
}
public Computer(String brand, String type, String sn, Float price) {
this.brand = brand;
this.type = type;
this.sn = sn;
this.price = price;
}
@Override
public String toString() {
return "Computer{" +
"brand='" + brand + '\'' +
", type='" + type + '\'' +
", sn='" + sn + '\'' +
", price=" + price +
'}';
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getSn() {
return sn;
}
public void setSn(String sn) {
this.sn = sn;
}
public Float getPrice() {
return price;
}
public void setPrice(Float price) {
this.price = price;
}
}
applicationContext.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="c1" class="pers.thc.spring.IoC.companyProperties.entity.Computer">
<constructor-arg name="brand" value="华硕"/>
<constructor-arg name="type" value="笔记本电脑"/>
<constructor-arg name="sn" value="18977240383"/>
<constructor-arg name="price" value="9880.0"/>
</bean>
<bean class="pers.thc.spring.IoC.companyProperties.entity.Computer">
<constructor-arg name="brand" value="华硕"/>
<constructor-arg name="type" value="笔记本电脑"/>
<constructor-arg name="sn" value="8943464678"/>
<constructor-arg name="price" value="9880.0"/>
</bean>
<bean class="pers.thc.spring.IoC.companyProperties.entity.Computer">
<constructor-arg name="brand" value="微星"/>
<constructor-arg name="type" value="笔记本电脑"/>
<constructor-arg name="sn" value="4964613786"/>
<constructor-arg name="price" value="9880.0"/>
</bean>
<bean id="company" class="pers.thc.spring.IoC.companyProperties.entity.Company">
<property name="rooms">
<list>
<value>2001-总裁办</value>
<value>2003-总经理办公室</value>
<value>2010-研发部会议室</value>
</list>
</property>
<property name="computers">
<map>
<entry key="dev-88172" value-ref="c1"/>
<entry key="dev-88173">
<bean class="pers.thc.spring.IoC.companyProperties.entity.Computer">
<constructor-arg name="brand" value="华硕"/>
<constructor-arg name="type" value="笔记本电脑"/>
<constructor-arg name="sn" value="18977240384"/>
<constructor-arg name="price" value="9880.0"/>
</bean>
</entry>
<entry key="dev-88174">
<bean class="pers.thc.spring.IoC.companyProperties.entity.Computer">
<constructor-arg name="brand" value="联想"/>
<constructor-arg name="type" value="台式机"/>
<constructor-arg name="sn" value="18977240385"/>
<constructor-arg name="price" value="19880.0"/>
</bean>
</entry>
</map>
</property>
<property name="info">
<props>
<prop key="phone">0772-3626316</prop>
<prop key="address">广西省柳州市城中区八一路XX路XX栋XXXX室</prop>
<prop key="website">http://www.xxx.com</prop>
</props>
</property>
</bean>
</beans>
Application类
package pers.thc.spring.IoC.companyProperties;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import pers.thc.spring.IoC.companyProperties.entity.Company;
import pers.thc.spring.IoC.companyProperties.entity.Computer;
public class CompanyPropertiesApplication {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext-company-properties.xml");
Company company = context.getBean("company", Company.class);
System.out.println(company);
//获取容器内所有beanId数组
String[] names = context.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
Computer computer = context.getBean("pers.thc.spring.IoC.companyProperties.entity.Computer#1", Computer.class);
System.out.println(computer);//获取匿名bean的方法-2,通过类名全称#序号来获取相应的bean对象。序号为0,1,2……,按applicationContext.xml中的顺序递推
}
}
bean scope属性:
-
bean scope属性用于决定对象何时被创建与作用范围
-
bean scope配置将影响容器内对象的数量
-
默认情况下bean会在IoC容器创建后自动实例化,全局唯一
bean scope属性清单:
-
singleton 单例(默认值),每一个容器有且只有唯一的实例,实例会被全局共享。单例多线程,但存在线程安全风险。 singleton线程安全问题,a=2(用户1)a.setNum(1)->a对象num=1,(用户2)sout(a.getNum())->本应输出2,现输出1
-
prototype 多例,每次使用时都会创建一个实例
-
request web环境下,每一次独立请求存在唯一实例
-
session web环境下,每一次session存在有唯一实例
-
global session portlet的web应用的共享session中
-
websocket 每一次websocket连接中存在唯一实例
singleton(左)和prototype(右)对比:
-
对象数量:全局唯一 存在多个
-
实例化时机:IoC容器启动时 getBean()或对象注入时
-
线程安全问题: 存在 不存在
-
执行效率:高 低
bean的生命周期:
-
容器行为:Ioc容器准备初始化解析XML->为对象注入属性->IoC容器初始化完毕->IoC容器准备销毁
-
对象行为:对象实例化执行构造方法->调用init-method初始化方法->执行业务逻辑->调用destroy-method释放资源
Order实体类
package pers.thc.spring.IoC.lifecycle;
public class Order {
private Float price;
private Integer quantity;
private Float total;
public Order(){
System.out.println("创建Order对象,"+this);
}
public void init(){
System.out.println("执行init()方法");
total=price*quantity;
}
public void destroy(){
System.out.println("释放与订单对象相关的资源");
}
public void pay(){
System.out.println("订单金额为:"+total);
}
public Float getPrice() {
return price;
}
public void setPrice(Float price) {
System.out.println("设置price:"+price);
this.price = price;
}
public Integer getQuantity() {
return quantity;
}
public void setQuantity(Integer quantity) {
System.out.println("设置quantity:"+quantity);
this.quantity = quantity;
}
public Float getTotal() {
return total;
}
public void setTotal(Float total) {
this.total = total;
}
}
application Context.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="order1" class="pers.thc.spring.IoC.lifecycle.Order" init-method="init" destroy-method="destroy">
<property name="price" value="23.0"/>
<property name="quantity" value="10"/>
</bean>
</beans>
Application类
package pers.thc.spring.IoC.lifecycle;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class LifeCycleApplication {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext-lifecycle.xml");
System.out.println("========IoC容器已初始化========");
Order order1 = context.getBean("order1", Order.class);
order1.pay();
context.registerShutdownHook();//调用destroy-method方法销毁bean实例
}
}
注解开发: 三类注解
-
组件装配注解-声明当前类的功能和职责 四类组件类型注解:
-
@Component 组件注解,通用注解,被注解描述的类将被IoC容器管理并实例化
-
@Controller 语义注解,MVC控制层
-
@Service 语义注解,MVC业务层
-
@Repository 语义注解,MVC数据持久化层 开启组件扫描: <context:component-scan package="pers.thc"> <context:exclude-filter type="regex" expression="pers.thc.exl*"/> /context:component-sacn
-
-
自动装配注解-根据属性特征自动注入对象 两类自动装配注解:
-
按类型装配:
-
@Autowired 按容器内对象类型动态诸如属性,由Spring机构提供
-
@Inject 基于JSR-330(Denpendency Inject for java)标准,其他同@Autowired,但不支持required属性
-
-
按名称装配:
-
@Named 与@Inject配合使用,JSR-330标准,按属性名自动装配属性
-
@Resource 基于JSR-250规范,优先按名称、再按类型智能匹配
-
-
-
元数据注解-更细化的辅助IoC容器管理对象的注解
-
@Primary 按类型装配时出现多个相同类型对象,拥有此注解对象优先被注入
-
@PostConstruct 描述方法,相当于XML中init-method配置的注解版本
-
@PreDestroy 描述方法,相当于XML中destroy-method配置的注解版本
-
@Scope 设置对象的scope属性
-
@Value 为属性注入静态数据
-
使用Java Config配置IoC容器: Java Config核心注解
-
@Configuration 描述类,说明当前类时Java Config配置类,完全替代XML文件
-
@Bean 描述方法,方法返回对象将被IoC容器管理,beanId默认为方法名
-
@ImportResource 描述类,加载静态文件,可以使用@Value注解获取
-
@ComponentScan 描述类,同XML的context:component-scan标签
Spring与JUnit4整合
-
Maven工程依赖spring-test
-
利用@RunWith(让Spring接管JUnit4的控制权)与@ContextConfiguration(初始化过程中加载哪个初始化文件)描述测试用例类
-
测试用例类从容器获取对象完成测试用例的执行
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import pers.thc.spring.IoC.springtest.service.UserService;
import javax.annotation.Resource;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext-test.xml"})
public class SpringTestor {
@Resource
private UserService userService;
@Test
public void testUserService(){
userService.createUser();
}
}