Spring 基础与核心概念
spring 是包含了众多工具方法的 IoC 容器。
什么是 IoC ?
IoC = Inversion of Control 翻译成中⽂是"控制反转"的意思,也就是说 Spring 是⼀个"控制反转"的容
器。控制反转,更确切的理解是控制权的反转。要理解控制反转,我们从以下实例出发:
以开发一辆汽车为例:
传统开发:

控制反转后:

传统代码是 Car 控制并创建了Framework,Framework 创建并创建了 Bottom,依次往下,⽽改进之后的控制权发⽣的反转,不再是上级对象创建并控制下级对象了,⽽是下级对象把注⼊将当前对象中,下级的控制权不再由上级类控制了,这样即使下级类发⽣任何改变,当前类都是不受影响的,这就是典型的控制反转,也就是 IoC 的实现思想。
Spring 的核心功能:如何将对象存入到Spring当中,如何从Spring当中获取对象。
DI 介绍: dependency injection 依赖注入
所谓依赖注⼊,就是由 IoC 容器在运⾏期间,动态地将某种依赖关系注⼊到对象之中。
简单小结:Spring 是一个框架,IoC 是一种思想,DI 是 IoC 的具体实现。
创建Spring项目:
创建一个普通的maven项目:


添加Spring依赖:
1.对当前项目和新项目配置国内源:


2.更改setting.xml 中的镜像

3.删除原repository中的文件,重新加载:


4.引入依赖:

添加启动类:

将Bean对象存储到Spring容器中并获取和使用
- 创建一个Bean,在Java当中,如果一个类被多次调用,那么就可以称之为Bean.

2.将Bean存储到spring容器中

3.从Bean中获取对象


获取 Bean 的三种方式:
- 通过名称获取:不推荐

- 通过类名获取:不推荐

当一个类在 spring 中存储多份时,使用该方法出错:

- 推荐的方式:通过名称+类名的方式:

更为简单的存储和获取 Bean 对象的方式:注解
常用的几大类注解:


前置工作:配置扫描路径


得到Bean对象:其中得S有两种命名规则,若原类名得第一个字母和第二个字母均为大写,则S为原类名,若不是,则将原类名得第一个字母变为小写后使用:


不同包下出现同名类时:在对类进行存储时起别名,否则会报错,尽量避免两个类名相同。

五大类注解有什么关系?

为什么需要五大类注解:
为了方便程序员更好得区分当前类得作用。
JavaEE标准分层:

阿里标准分层:

实体类的命名规则:

使用方法注解@Bean 存储对象到spring容器中:
Bean是将方法得返回值存入spring,因此使用Bean注解得方法必须有返回值。

Bean 重命名:

同一个类型的对象存储多份时,后者会将前者覆盖,通过@Order注解来控制存入的顺序,值为1-100,数字越小先存入,后者将前者覆盖。


输出结果为:张三。
获取Bean对象
在当前基于Spring_core 框架的项目中,无法在启动类的main方法中获取到Bean对象,因为当前static修饰的类加载优先于Bean。
1.属性注入

单一设计原则:一个类只实现一个功能,当一个类中通过属性注入多个对象时,就会违背单一设计原则。
2.setter注入

3.构造方法的注入

@Resource 和 @Autowired 的区别:
1.两者来源不同,前者来自 JDK,后者来自 Spring.
2.两者都可以用于对象注入,但是前者不能用于构造方法的注入
3.前者拥有更多的属性内容,后者只有是否必须加载一个属性:

4.在Spring容器中,查找Bean的方式有两种,一种是按照类型查找,一种是按照名称查找,@Autowired 注解先根据类型查找,再根据名称查找,而@Resource注解刚好相反。
Lombok 的使用
- 引入依赖:

- 在实体类上使用其提供的注解

- 装Lombok插件:

Bean 的作用域和生命周期
先来看一个例子:
创建实体类:

原始数据:

在controller中分别注入当前的数据,并在第一个中进行数据修改:


在启动程序中调用两个controller:

此时,我们发现,当一个Bean被修改后,别处获取到的Bean数据也发生了改变。
Bean 作用域默认是单例模式 = 该 Bean 在整个spring容器中只存在一份。


spring 的执行流程:

Bean 的生命周期:从诞生到销毁
-
开辟内存空间,进行Bean的实例化;
-
设置属性(属性注入):在初始化时可能会使用到属性,因此要先进行属性注入;
-
初始化
3.1 各种通知
3.2 初始化前置方法
3.3 初始化方法(两种实现方式,一种是xml,一种是通过注解)
3.4 初始化后置方法
-
使用Bean
-
销毁Bean
代码示例:
typescript
public class ComponentBeans implements BeanNameAware, BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化前置方法");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化后置方法");
return bean;
}
@Override
public void setBeanName(String s) {
System.out.println("通知 setBeanName "+ s);
}
public void myInit(){
System.out.println("XML 方式的初始化方法");
}
@PostConstruct
public void doPostConstruct(){
System.out.println("注解方式的初始化方法");
}
public void saiHi(){
System.out.println("使用Bean");
}
@PreDestroy
public void doPreDestroy(){
System.out.println("执行了销毁方法");
}
}
arduino
public class App {
public static void main(String[] args) {
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("spring-config.xml");
ComponentBeans componentBeans = context.getBean("componentBeans",ComponentBeans.class);
componentBeans.saiHi();
context.close();
}
}
输出结果:

说明:
-
为何通知执行了两次,一次是在new 对象时进行初始化,一次是在getBean 时初始化;
-
为何没有执行销毁方法,因为多例模式下,销毁bean是直接停止线程,故不会执行销毁时的方法。
-
前置方法和后置方法只有作用域为原型模式时才执行。