Spring框架-IoC-DI

Spring框架概述

Spring 是一个轻量级的 DI/IoC 和 AOP 容器的开源框架,致力于构建轻量级的 JavaEE 应用.

容器

容器还要管理对象的生命周期,如 Tomcat 就是 Servlet 和 JSP 的容器

架构

1.Core Container(核心容器)包含有 Beans、Core、Context 和 SpEL 模块。
2.Data Access/Integration 层包含有 JDBC、ORM、OXM、
3.JMS 和 Transactions 模块。
4.Web 层包含了 Web、Servlet、WebSocket、Porlet 模块。 
5.AOP 模块提供了遵循 AOP 联盟标准的面向切面编程的实现。 
6.Test 模块支持使用 JUnit 和 TestNG 对 Spring 组件进行测试。

IoC和DI思想

IoC:Inversion of Control(反转控制)
将原本在程序中手动创建对象的控制权,交由 Spring 框架的 IoC 容器来管理.调用者只管负责从 Spring 容器中获取需要使用的对象,不关心对象的创建过程,也不关心该对象依赖对象的创建以及依赖关系的组装,也就是把创建对象的控制权反转给了 Spring 框架.

IoC_Demo

domain:

1
2
3
4
5
6
7
8
9
10
11
12
public class HelloWorld {
private String name;
private int age;
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void sayHello() {
System.out.println(name + "你好,年龄" + age); }
}

XML 配置:

1
2
3
4
5
6
7
8
9
10
<?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="helloWorld" class="...HelloWorld">
<property name="name" value="will"/> 对应HelloWorld中的setName方法
<property name="age" value="17" /> 对应 HelloWorld 中的 setAge 方法
</bean>
</beans>

测试类:

1
2
3
4
5
6
7
8
HelloWorld world = null;
//加载 Spring 配置文件 applicationContext.xml
Resource resource = new ClassPathResource("applicationContext.xml");
//创建 Spring 容器对象
BeanFactory factory = new XmlBeanFactory(resource);
//从 Spring 容器中获取制定名为 helloWorld 的 bean
world = (HelloWorld) factory.getBean("helloWorld");
world.sayHello();

BeanFactory

Spring IoC 容器——生产 bean 对象的工厂,负责配置,创建和管理 bean.
被 Spring IoC 容器管理的对象称之为 bean

Spring IoC 管理 bean 的原理:

1.通过 Resource 对象加载配置文件
2.解析配置文件,得到指定名称的 bean
3.解析 bean 元素,id 作为 bean 的名字,class 用于反射得到 bean 的实例:注意:此时,bean 类必须存在一个无参数构造器(反射创建:和访问权限无关);
4.调用 getBean 方法的时候,从容器中返回对象实例;

就是把代码从 JAVA 文件中转移到了 XML 中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
HelloWorld wolrd = null;
String className="...HelloWorld";
//-----------------------------------------------------
Class clz = Class.forName(className);
Constructor con = clz.getDeclaredConstructor();
con.setAccessible(true);
wolrd = (HelloWorld)con.newInstance();
BeanInfo beanInfo = Introspector.getBeanInfo(wolrd.getClass());
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor pd : pds) {
String propertyName = pd.getName();
Method setterMethod =pd.getWriteMethod();
if("name".equals(propertyName)){
setterMethod.invoke(wolrd, "Will");
}else if("age".equals(propertyName)) {
setterMethod.invoke(wolrd, 17);
} }
//-----------------------------------------------------
wolrd.sayHello();

getBean 方法签名

方式一:按照 bean 的名字拿 bean,按照名字拿 bean 不太安全

1
world = (HelloWorld) factory.getBean("helloWorld");

方式二:按照类型拿 bean,要求在 Spring 中只配置一个这种类型的实例

1
world = factory.getBea (HelloWorld.class);

方式三:按照名字+类型(推荐)

1
world = factory.getBean("helloWorld",HelloWorld.class);

bean元素id,name和import

id:可以使用字母、数字、连字符、下划线、句话、冒号,不能以“/”开头(spring3.1之前)
name:使用 name 属性为 bean 元素起多个别名,多个别名之间使用逗号或空格隔开.

import resource:将一个
applicationContext.xml 文件分解成多个配置文件,然后在 applicationContext.xml 文件中包含其他配置文件

1
<import resource="classpath:路径1/路径2/hello.xml"/>

Spring 测试框架

基于 JUnit4 的测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:springTest.xml")
public class SpringTestTest {

@Autowired
private HelloWorld world;

@Test
public void test1() throws Exception {

world.sayHello();
}
}

@ContextConfiguration
默认去找的当前测试类名-context.xml 配置文件,如:SpringTestTest-context.xml

IoC 容器

BeanFactory:
Spring 最底层的接口,只提供了的 IoC 功能,负责创建、组装、管理 bean,在应用中一般不使用 BeanFactory
ApplicationContext:
ApplicationContext 接口继承了BeanFactory,除此之外还提供 AOP 集成、国际化处理、事件传播、统 一资源价值等功能.

bean实例化方式

2.静态工厂方法实例化:解决系统遗留问题
3.实例工厂方法实例化:解决系统遗留问题

必须保证 SomeBean1 必须有无参数构造器,和访问权限无关
1.构造器实例化(无参数构造器),最标准,使用最多.

1
2
3
4
5
public class SomeBean1 {
public SomeBean1() {
System.out.println("SomeBean1 构造器"); }
}
<bean id="someBean1" class="...SomeBean1"/>

4.实现 FactoryBean 接口实例化:实例工厂变种
用于其他框架和 Spring 集成,如集成 MyBatis 使用:org.mybatis.spring.SqlSessionFactoryBean

1
2
3
4
5
6
7
8
9
10
11
public class SomeBean4 {
}
public class SomeBean4FactoryBean implements FactoryBean<SomeBean4>{
public SomeBean4 getObject() throws Exception {
//TODO
return new SomeBean4();
}
public Class<?> getObjectType() {
return SomeBean4.class;
} }
<bean id="someBean4" class="...SomeBean4FactoryBean"/>

Bean 作用域
1
<bean id="" class="" scope="作用域"/>

singleton: 单例
prototype: 多例,每次从容器中调用 Bean 时,都返回一个新的实例

Bean 初始化和销毁

1.init-method:bean 生命周期初始化方法,bean 对象创建后就进行调用.
2.destroy-method:容器被正常销毁的时候,如果 bean 被容器管理,会调用该方法.

DI 核心

1.所谓注入,可以简单理解为 IoC 容器创建对象的时候,设置相关的属性值.
2.给对象设置数据:
要么是在创建对象的时候通过构造器传入.
要么就是先创建对象,再通过setter 方法再设置
所以,注入方式主要有两种:

1.setter 方法注入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//注入常量
<property name="name" value="蛤蛤"/>
//注入对象
<property name="instance" ref="instance"/>
//注入集合
<property name="prop">
<props>
<prop key="pKey1">pVal1</prop>
<prop key="pKey2">pVal2</prop>
</props>
</property>
//简写
<property name="prop">
<value>
pKey1=pValue1
pKey2=pValue2
</value>
</property>

2.构造器注入:

构造器方式注入使用:

1
2
3
4
5
6
7
<constructor-arg/>元素

//安装构造器的参数名字设置值
<constructor-arg name="name" value="will"/>
<constructor-arg name="age" value="17" />
<constructor-arg name="other" ref="otherBean"/>
<constructor-arg name="prop">

配置连接池

1
2
3
4
5
6
7
8
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
init-method="init" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/springdemo"/>
<property name="username" value="root"/>
<property name="password" value="admin"/>
<property name="initialSize" value="5"/>
</bean>

抽取 db.properties 文件

1
2
3
4
5
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///springdemo
jdbc.username=root
jdbc.password=admin
jdbc.initialSize=5