目录
一、什么是Spring
1.1容器
1.2什么是IoC
传统方式创建对象的问题: 类与类之间的耦合性过大
Ioc的优点
Spring IoC容器最核心的功能
1.3DI概念说明(Dependency Injection)
IoC和DI的区别是什么
二、Spring项目的创建
三、Spring的使用(把对象存储到spring当中)
3.1添加spring的配置文件
3.2先创建一个bean对象
3.3在配置文件当中,配置需要存储的对象
3.4从spring容器当中读取出这一个bean
使用ApplicationContext来获取对象
步骤1:得到spring的上下文对象(写法1:使用ApplicationContext)
步骤2:根据spring上下文对象(context)提供的getbean方法来获取到对象
注意事项
使用BeanFactory来获取对象
ApplicationContext和BeanFactory的区别是什么
1、ApplicationContext是属于BeanFactory的子类。
2、性能不同(饿加载、懒加载)
关于getBean的更多用法
用法1:getBean(传入的字符串是对象的名称)
用法2:根据bean的类型来获取bean
用法3:根据bean name和类型获取bean
先总览概括一下:Spring方法是一个包含了众多工具方法的IoC容器。
容器是用来容纳某种物品的基本装置。
例如我们之前学的:
lIst是容器,用来装载一些元素。
Tomcat是容器,用来存放Web应用程序的容器。
那么,同理:Spring也是一个Ioc的容器。
在聊Ioc之前,我们先聊一下传统new创建对象的问题:
举一个例子:如果想要创造一个汽车"car"模型出来,那么,按照传统的思想,是这样创造的:
如果按照代码实现,那么就是这样的:在每一层都new下一层的对象。
如果想要修改最底层的类的信息,那么就需要沿着调用栈一直往上修改。
但是,如果新增一个需求:就是要允许用户输入轮胎的属性,来生成不同的轮胎大小,那么这样的话,可能就需要从头到尾一直修改(给每一个方法都新增一个size参数)
因此,可以这样修改:在每一层当中,提供一个属性引用,指向下一层的对象。
public class Car {
/**
* 保存下一级调用的引用
*/
private Frame frame;
/**
* 令这个引用指向下一级的对象
* frame对象@param frame
*/
public Car(Frame frame){
this.frame=frame;
}
/**
* 执行下一级的逻辑
*/
public void init(){
frame.init();
}
//车架类
static class Frame{
/***
* 这个引用指向下一级的轮胎类
*/
private Tire tire;
public Frame(Tire tire){
this.tire=tire;
}
public void init(){
tire.init();
}
}
//轮胎类
static class Tire{
private int size;
public Tire(int size){
this.size=size;
}
public void init() {
System.out.println("轮胎的大小是:"+this.size);
}
}
public static void main(String[] args) {
//首先,创建一个轮胎类,制定大小
Tire tire=new Tire(20);
//然后,创建一个车架类,把轮胎作为属性传递进去
Frame frame=new Frame(tire);
//最后,创建一个car类,把frame作为属性传递下去
Car car=new Car(frame);
}
}
这样子修改,可以看到,假如需要修改tire,想要新增参数,那么就只用改动两个地方:
一个地方是Tire类的属性,另外一个是main方法当中实例化tire对象的参数。
中间的调用过程全都不用修改。每一层之间的耦合度降低了许多。
实现代码的解耦,把对象(Bean)的生命周期交给了IoC框架来维护,作为程序员无需再次关注了。
通过代码的实现,可以发现:不再是上级对象创建并且控制下一级对象了。而是把下一级的对象注入到上一级的对象当中。也就是把控制对象生命周期的权力交给了IoC容器。
1、将对象(Bean)存储到Spring(容器)当中。
2、将对象(Bean)从Spring(容器)当中取出来。
翻译成中文就是:依赖注入的意思。
指的是把对象(Bean)注入到IoC容器当中,如果外界想要获取这一个对象,就可以从IoC当中获取
IoC是一种思想,这种思想就是:控制反转,把对象的生命周期交给IoC容器。DI就是IoC思想的一种实现,也就是IoC思想是依靠DI这种方式来实现的。
这就好像乐观锁和CAS的关系一样:乐观锁这种思想是依靠CAS这种机制来实现的
第一步:创建一个maven项目;
第二步:在maven项目当中添加spring支持。
这两个支持分别是:(spring-context/spring-beans)
第三步:编写一个测试的main方法
在maven当中导入的内容如下:
org.springframework
spring-context
5.2.15.RELEASE
org.springframework
spring-beans
5.2.15.RELEASE
然后,创建一个App类,用于测试后面的代码。
public class Application {
public static void main(String[] args) {
System.out.println("hello spring");
}
}
任意新建一个对象即可。
需要使用到bean标签,
里面要指定id属性:这个属性的含义是指定对象的名称。
还需要指定class属性:这个属性的含义是类的文件路径。
在spring容器当中,bean的存储就是按照:一个类似于哈希表的结构:
Map
其中,id属性对应的对象名称相当于一个key,对应的对象相当于一个value。
//需要在此处得到spring配置文件的名称
ApplicationContext context=new ClassPathXmlApplicationContext("spring-config.xml");
//此处的对象名称一定要和配置文件当中的id一样
User user= (User) context.getBean("user");
另外,还可以使用BeanFactory来获取对象。
代码整体实现:
public static void main(String[] args) {
//需要在此处得到spring配置文件的名称
ApplicationContext context=new ClassPathXmlApplicationContext("spring-config.xml");
//此处的对象名称一定要和配置文件当中的id一样
User user= (User) context.getBean("user");
user.say("张三");
}
使用getBean(bean的名称)这种方式来获取bean的时候,需要注意:
1、一个容器当中不可以出现相同的id名称,否则运行时候会报错。
2、getBean方法传入的参数一定要在xml文件当中指定、
跟上面的步骤类似,也是需要经历下面的几个步骤
public static void main(String[] args) {
//得到bean工厂
BeanFactory beanFactory=new XmlBeanFactory(new ClassPathResource("spring-config.xml"));
//获取bean对象
User user= (User) beanFactory.getBean("user");
//使用bean
user.say("李四");
}
相同点:都可以从Ioc容器当中获取bean。
不同点:
ApplicationContext继承于BeanFactory。BeanFactory只提供了最基础的访问bean的方法,而ApplicationContext除了拥有BeanFactory以外,还拥有一些其他的机制,例如:支持国际化等等.....后面的文章会说明
ApplicationContext采用的是"饿加载"的方式来进行加载的。而BeanFactory采用的是"懒加载"的方式来进行加载的。
当在xml的配置文件当中配置了多个bean的时候,
如果使用ApplicationContext会一次加载所有的bean。
如果使用BeanFactory,那么仅仅只会在调用getBean方法时候指定了对应的bean的名称之后,找到了Bean对象,才会进行加载。
//获取bean对象
User user= (User) beanFactory.getBean("user");
这个方法返回的是一个Object类型的对象,并且不允许spring容器当中存在多个名称为user的bean
此时传入getBean方法的参数就是需要获取类型的字节码对象(class对象)
public static void main(String[] args) {
//得到bean工厂
BeanFactory beanFactory=new XmlBeanFactory(new ClassPathResource("spring-config.xml"));
//无需强制类型转换
User user=beanFactory.getBean(User.class);
user.say("小明");
}
好处:避免了强制类型转换。
坏处:当同一个类在spring容器当中注入了两个不同的对象的时候,就会抛出异常。
抛出异常:NoUniqueBeanDefinitionException
public static void main(String[] args) {
//得到bean工厂
BeanFactory beanFactory=new XmlBeanFactory(new ClassPathResource("spring-config.xml"));
//无需强制类型转换
//传入的第一个参数为bean的名称:对应到bean属性的id值
//传入的第二个参数为获取对象的类型
User user=beanFactory.getBean("user",User.class);
user.say("小明");
}
这一种做法,相比于前两种,代码的健壮性明显提升了。既可以通过beanName来锁定需要获取哪一个bean,又可以校验需要获取bean的名称。