一、IoC和DI
1、IoC:Inverse of Control(控制反转):读作“反转控制”,更好理解,不是什么技术,而是一种设计思想,好比于MVC。就是将原本在程序中手动创建对象的控制权,交由Spring框架来管理。
-
正控:若调用者需要使用某个对象,其自身就得负责该对象的创建。
-
反控:调用者只管负责从Spring容器中获取需要使用的对象,不关心对象的创建过程,也就是把创建对象的控制权反转给了Spring框架。
2、DI:Dependency Injection(依赖注入)
从字面上分析:
-
IoC:指将对象的创建权,反转给了Spring容器;
-
DI :指Spring创建对象的过程中,将对象依赖属性(简单值,集合,对象)通过配置设值给该对象。
IoC和DI其实是同一个概念的不同角度描述,DI相对IoC而言,明确描述了“被注入对象依赖IoC容器配置依赖对象”。
3、Container:容器
在生活中容器就是一种盛放东西的器皿,从程序设计角度看作是装对象的对象,因为存在对对象的存入、取出等操作,所以容器还要管理对象的生命周期。
二、Spring初体验
1、依赖jar包
- spring-beans-5.1.0.RELEASE.jar
- spring-core-5.1.0.RELEASE.jar
- commons-logging-1.2.jar(spring依赖包)
2、创建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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 把对象的创建权交给Spring
id:给当前<bean/>起唯一的标识名称,也作为创建对象的名称、
class:需要交给 Spring 管理类的权限定名
-->
<bean id="hello" class="com.revanwang.ioc.HelloWorld">
<!--给bean注入值-->
<property name="username" value="Revan"/>
</bean>
</beans>
3、HelloWorld
package com.revanwang.ioc;
import lombok.Setter;
public class HelloWorld {
@Setter
private String username;
public void sayHello() {
System.out.println("你好,Spring " + this.username);
}
}
4、从容器中获取bean对象
public void testIoC() {
//1、从classpath根路径加载资源文件,创建资源对象
Resource resource = new ClassPathResource("applicationContext.xml");
//2、创建Spring对象
BeanFactory factory = new XmlBeanFactory(resource);
//3、从Spring容器中获取指定id名称的对象
HelloWorld world = (HelloWorld) factory.getBean("hello");
world.sayHello();
}
三、Spring原理
1、BeanFactoory
Spring最基本的接口,表示Spring容器:生产bean对象的工厂,负责配置,创建和管理bean。
- bean是Spring管理的单位,在Spring中一切都是bean
2、Spring管理bean的原理
- 1、通过Resource对象加载配置文件
- 2、解析配置文件(applicationContext.xml),得到指定名称的bean
- 3、解析bean元素,id作为bean的名称,用来从Spring获取bean对象的标识,class用于反射得到bean的实例
Class clz = Class.forName("com.revanwang.ioc.HelloWorld");
Constructor con = clz.getDeclaredConstructor();
con.setAccessible(true);
HelloWorld obj = (HelloWorld)con.newInstance();
//--------------------------------------
BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor pd : pds) {
if("name".equals(pd.getName())){
Method setterMethod =pd.getWriteMethod();
setterMethod.invoke(obj, "Revan");
break;
}
}
obj.sayHello();
- 4、调用getBean方法的时候,从容器中返回对象实例
注意:
1、这种配置下,所有的bean保证有一个无参数构造器(和访问权限无关)
2、把代码从Java文件中 转移 到了XML中
3、getBean方法的三种签名
方法一:按照类型拿bean
注意:要求在Spring中只能配置一个这种类型的实例,否则报错
@Test
public void testIoC() {
//1、从classpath根路径加载资源文件,创建资源对象
Resource resource = new ClassPathResource("applicationContext.xml");
//2、创建Spring对象
BeanFactory factory = new XmlBeanFactory(resource);
//3、从Spring容器中获取指定id名称的对象
// HelloWorld world = (HelloWorld) factory.getBean("hello");
//按照类型拿bean
HelloWorld world = factory.getBean(HelloWorld.class);
world.sayHello();
}
方法二:按照bean的名字拿bean
注意:按照名字拿bean不是太安全
@Test
public void testIoC() {
//1、从classpath根路径加载资源文件,创建资源对象
Resource resource = new ClassPathResource("applicationContext.xml");
//2、创建Spring对象
BeanFactory factory = new XmlBeanFactory(resource);
//3、从Spring容器中获取指定id名称的对象
HelloWorld world = (HelloWorld) factory.getBean("hello");
//按照类型拿bean
//HelloWorld world = factory.getBean(HelloWorld.class);
world.sayHello();
}
方法三:按照bean的名字和类型拿bean(推荐使用)
@Test
public void testIoC() {
//1、从classpath根路径加载资源文件,创建资源对象
Resource resource = new ClassPathResource("applicationContext.xml");
//2、创建Spring对象
BeanFactory factory = new XmlBeanFactory(resource);
//3、从Spring容器中获取指定id名称的对象
//HelloWorld world = (HelloWorld) factory.getBean("hello");
//按照类型拿bean
//HelloWorld world = factory.getBean(HelloWorld.class);
HelloWorld world = factory.getBean("hello", HelloWorld.class);
world.sayHello();
}
四、Spring的基本配置
4.1:在Spring配置中,id和name属性都可以定义bean元素的名称,不同的是:
- id属性,遵守XML语法的ID约束(唯一)。必须以字母开始,可以使用字母、数字、连字符、下划线、句话、冒号,不能以“/”开头。
- name属性,就可以使用很多特殊字符,比如在Spring和Struts1或Spring MVC的整合中,就得使用name属性来的定义bean的名称。
<bean id="hello" class="com.revanwang.ioc.HelloWorld">
<!--给bean注入值-->
<property name="username" value="Revan"/>
</bean>
注意:从Spring3.1开始,id属性不再是ID类型了,而是String类型,也就是说id属性也可以使用“/”开头了,而bean元素的id的唯一性由容器负责检查。当然也使用name属性为<bean/>元素起多个别名,多个别名之间使用逗号或空格隔开,在代码中依然使用BeanFactory对象.getBean(...)方法获取。
<bean id="hello, h" class="com.revanwang.ioc.HelloWorld"/>
OR
<bean id="hello h" class="com.revanwang.ioc.HelloWorld"/>
建议:bean起名尽量规范,不要搞一些非主流的名字,尽量使用id。
4.2:Spring中引入其他配置文件
在实际开发中,随着应用规模的增加,系统中<bean>元素配置的数量也会大量增加,导致applicationContext.xml配置文件变得非常臃肿。为了避免applicationContext.xml文件过于庞大、臃肿,为提高其可读性,我们可以将一个applicationContext.xml文件分解成多个配置文件,然后在applicationContext.xml文件中包含其他配置文件即可。
使用import元素引入其他的配置文件:
<import resource="classpath:com/revanwang/ioc/hello.xml"/>
使用import元素注意:
1、默认情况下,从classpath的跟路径寻找。
2、可以使用前缀来定位文件的基础位置:
①:[classpath:]:后面的文件从classpath路径开始找(推荐);[注意classloader的问题。]
②:[file:]:后面的文件使用文件系统的路径开始找;
注意:只有当框架中实现了Resource接口才能够识别上述的前缀标识符。
五、Spring测试
5.1、传统的测试
传统的测试存在问题:
- 1,每个测试都要重新启动Spring容器,启动容器的开销大,测试效率低下。
- 2,不应该是测试代码管理Spring容器,应该是Spring容器在管理测试代码。
5.2、Spring测试
jar包
- junit-4.12.jar
- spring-test-5.1.0.RELEASE.jar
- spring-context-5.1.0.RELEASE.jar
- spring-expression-5.1.0.RELEASE.jar
- spring-aop-5.1.0.RELEASE.jar
ContextConfiguration
- @ContextConfiguration("classpath:applicationContext.xml")
- ContextConfiguration:默认去找的当前测试类名-context.xml配置文件,如:HelloWorldTest-context.xml
package com.revanwang.ioc;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
//告诉JVM,Spring容器直接运行在JVM中
@RunWith(SpringJUnit4ClassRunner.class)
//加载配置文件
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringTest {
@Autowired
private BeanFactory factory;
@Test
public void test1() {
HelloWorld helloWorld = factory.getBean("hello", HelloWorld.class);
helloWorld.sayHello();
}
}
SpringTest.png
网友评论