Spring 的核心功能就是在于其为企业级开发提供给了丰富的功能,但是这些功能的底层都依赖于它的两个核心特性,也就是依赖注入(IOC)和面向切面编程(AOP)
什么是是IOC?
控制反转。它把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理。所谓的“控制反转”概念就是对组件对象控制权的转移,从程序代码本身转移到了外部容器。(管理程序的调用执行不再是Java对象,而是一个个Bean容器)
Spring IOC 负责创建对象,管理对象(通过依赖注入(无需通过创建对象,再手动setXX去设置,而是通过配置赋值),装配对象,配置对象,并且管理这些对象的整个生命周期
依赖注入的几种方式:
- 构造函数注入
- setter 注入
- 接口注入(Spring4开始已废弃)
Spring 如何设计容器的?
什么是容器? 容器的作用又是哪些?
作用:
- 可以用来装载最基本的组件(一系列的Bean)
- 对装载的东西进行生到死的管理(生命周期)
- 组装组件的各个部件(属性值,加载方式)
具体实现Spring自动注入的有两大核心接口: BeanFactory和ApplicationContext
但BeanFactory和ApplicationContext又是怎样的关系?
BeanFactory和ApplicationContext
从上图继承关系就可以看出
BeanFactory:是Spring里面最底层的接口,包含了各种Bean的定义,读取bean配置文档,管理bean的加载、实例化,控制bean的生命周期,维护bean之间的依赖关系。
ApplicationContext接口作为BeanFactory的派生,除了提供BeanFactory所具有的功能外,还提供了更完整的框架功能:
- 继承MessageSource,因此支持国际化。
- 统一的资源文件访问方式。
- 提供在监听器中注册bean的事件。
- 同时加载多个配置文件。
- 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层。
容器是如何注入Bean的?
IoC 在 Spring 里,只需要低级容器就可以实现,2 个步骤:
加载配置文件,解析成 BeanDefinition 放在 Map 里。
调用 getBean 的时候,从 BeanDefinition 所属的 Map 里,拿出 Class 对象进行实例化,同时,如果有依赖关系,将递归调用 getBean 方法 —— 完成依赖注入。
注入容器涉及的注入模式
Spring 注入方式是通过工厂模式以及反射的形式注入的
interface Fruit {
public abstract void eat();
}
class Apple implements Fruit {
public void eat(){
System.out.println("Apple");
}
}
class Orange implements Fruit {
public void eat(){
System.out.println("Orange");
}
}
# 工厂模式
class Factory {
public static Fruit getInstance(String ClassName) {
Fruit f=null;
try {
// 反射
f=(Fruit)Class.forName(ClassName).newInstance(); } catch (Exception e) {
e.printStackTrace();
}
return f;
}
}
class Client {
public static void main(String[] a) {
Fruit f=Factory.getInstance("com.xxx.xxx.Apple");
if(f!=null){
f.eat();
}
}
}
Spring中Bean的生命周期
1、Spring 容器根据配置中的 bean 定义中实例化 bean。
2、Spring 使用依赖注入填充所有属性,如 bean 中所定义的配置。
3、 通过工厂传递 bean 的 ID 来调用setBeanName(),setBeanFactory()。
4、 bean 指定了 init 方法( 的 init-method 属性),那么将调用它。
5、最后,如果存在与 bean 关联的任何 BeanPostProcessors,则将调用 postProcessAfterInitialization() 方法。
6、,当 spring 容器关闭时,会调用 destory()。如果为 bean 指定了 destroy 方法( 的 destroy-method 属性),那么将调用它。
Spring中装配与自动装配?
Spring容器能够自动装配bean。也就是说,可以通过检查BeanFactory的内容让Spring自动解析bean的协作者。
自动装配的不同模式:
no
这是默认设置,表示没有自动装配 。 应使用显式 bean 引用进行装配 。
byName
它根据 bean 的名称注入对象依赖项 。 它匹配并装配其属性与 XML 文件中由相同名称定义的 bean。
byType
它根据类型注入对象依赖项。如 果属性的类型与 XML 文件中的一个 bean 名称匹配,则匹配并装配属性。
@Autowied 注入方式总结: 往IOC 容器中进行一个Select
spring IoC时,容器自动装载了一个AutowiredAnnotationBeanPostProcessor后置处理器,当容器扫描到@Autowied、@Resource或@Inject时,
就会在IoC容器自动查找需要的bean,并装配给该对象的属性。在使用@Autowired时,首先在容器中查询对应类型的bean:
如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据;
如果查询的结果不止一个,那么@Autowired会根据名称来查找;
如果上述查找的结果为空,那么会抛出异常。解决方法时,使用required=false。
什么是AOP 为什么使用AOP?
简单的来说是一种封装思想,但是这种封装后的方法,可以再某个模块的特定执行场景下,特定调用
AOP,一般称为面向切面编程,作为面向对象的一种补充,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect),减少系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。可用于权限认证、日志、事务处理等。
AOP涉及到的设计模式?
1. AOP中使用到的模式为: 代理模式
动态代理和静态代理
(实际上静态是在编译期确定(写死) 动态则是在运行时通过反射确定)
2. JDK动态代理和CGLIB动态代理的区别是什么?
Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理:
JDK动态代理只提供接口的代理,不支持类的代理。核心InvocationHandler接口和Proxy类,InvocationHandler 通过invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起;接着,Proxy利用 InvocationHandler动态创建一个符合某一接口的的实例, 生成目标类的代理对象。
如果代理类没有实现 InvocationHandler 接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。
CGLIB(Code Generation Library),通过类的继承的方式进行做代理
总结: 一个是接口实现方式,一个是类的继承方式(动态生成类的子类对象)
AOP具体实现方式?
Spring切面可以应用5种类型的通知:
前置通知(Before):在目标方法被调用之前调用通知功能;
后置通知(After):在目标方法完成之后调用通知,此时不会关心方法的输出是什么;
返回通知(After-returning ):在目标方法成功执行之后调用通知;
异常通知(After-throwing):在目标方法抛出异常后调用通知;
环绕通知(Around):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为。
总结: 给切面对应上相关连接点(执行方法 即为: 通知 )进行AOP操作