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容器中并获取和使用
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 的使用
Bean 的作用域和生命周期
先来看一个例子:
创建实体类:
原始数据:
在controller中分别注入当前的数据,并在第一个中进行数据修改:
在启动程序中调用两个controller:
此时,我们发现,当一个Bean被修改后,别处获取到的Bean数据也发生了改变。
Bean 作用域默认是单例模式 = 该 Bean 在整个spring容器中只存在一份。
spring 的执行流程:
Bean 的生命周期:从诞生到销毁
开辟内存空间,进行Bean的实例化;
设置属性(属性注入):在初始化时可能会使用到属性,因此要先进行属性注入;
初始化
3.1 各种通知
3.2 初始化前置方法
3.3 初始化方法(两种实现方式,一种是xml,一种是通过注解)
3.4 初始化后置方法
使用Bean
销毁Bean
代码示例:
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("执行了销毁方法");
}
}
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是直接停止线程,故不会执行销毁时的方法。
前置方法和后置方法只有作用域为原型模式时才执行。