spring重点知识分享
前言:
spring是一个轻量级的开源的控制反转(Inversion of Control,IOC)和面向切面(AOP)的容器框架,它的主要目的是简化企业开发。这两个模块使得java开发更加简单。IOC将对象的创建交给容器并且管理,达到了解耦的作用。增加对象的时候,不用改动代码,直接增加配置文件即可。Aop可以快速的添加某种功能。
1、IOC
1.1、ioc与其说是一门技术不如说是一种思想,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。 IOC又为控制反转,何为控制反转?java程序里把创建对象,以及对象之间的依赖交给容器去管理。代码创建对象需要去听过new一个,或者反射方式以及其他的方式。spring的容器可以创建和管理这些bean。通过xml文件或者通过注解就可以创建bean和管理bean。至于容器是有BeanFactory和ApplicationContext来创建的。
1.2、 ioc的实现方式:(1)使用XML配置的方式实现IOC. (2)注解实现 (3)依赖注入:构造方法和setter注入
1.3、ioc容器创建和管理的都是bean,所以最重要的都是bean。bean的创建和管理等原理见:https://juejin.im/post/5be976a76fb9a049fd0f5f31。
2、DI
IoC的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过DI(Dependency Injection,依赖注入)来实现的。
3、Junit单元测试 (后续添加)
4、AOP
切面(Aspect): 程序运行过程中的某个步骤或者阶段。
通知(advice): 在符合的连接点进行特殊的处理(增强处理)。
切入点(pointcut):可切入进行增强处理的连接点,AOP核心之一就是如何用表达式来定义符合的切入点。在Spring中,默认使用AspectJ的切入点语法。
连接点(joinpoint): 程序运行过程中可执行特定处理(增强处理)的点,如异常处理,在springAOP中,方法调用是连接点。
目标对象(target): 被进行增强处理的对象。
aop代理(AopProxy): 是一个重新封装了(增强处理 + 被代理对象的方法 )方法的代理对象。
织入(weaving): 增强处理切入目标对象以后,并获得代理对象(AOP代理)的这个过程,就是织入。按其作用的时间分类为,编译时织入与运行时织入。
AOP使用场景:权限控制、异常处理、缓存、事务管理、日志记录、数据校验等等。
Spring AOP中的动态代理主要有两种方式:JDK动态代理和CGLIB动态代理。
JDK动态代理,被代理的类必须要继承InvocationHandler接口,这个接口时JDK提供的,JDK动态代理:JDK动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。JDK动态代理的核心是InvocationHandler接口和Proxy类。为什么一定要继续接口呢?
1.在需要继承proxy类获得有关方法和InvocationHandler构造方法传参的同时,java不能同时继承两个类,我们需要和想要代理的类建立联系,只能实现一个接口。InvocationHandler中的invoke方法被自动调用。通过Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this);形成代理类。使用反射机制。
动态代理的第二种实现——CGlibcglib是针对类来实现代理的,原理是对指定的业务类生成一个子类,并覆盖其中业务方法实现代理。因为采用的是继承,所以不能对final修饰的类进行代理。
目标类没有实现接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成某个类的子类,注意,CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的,诸如private的方法也是不可以作为切面的。
实现 MethodInterceptor方法代理接口,创建代理类。通过代理类对象.getInstance(业务类对象) 返回一个动态代理类对象(它是业务类的子类,可以用业务类引用指向它)。最后通过动态代理类对象进行方法调用。使用ASM 非常强大的Java字节码生成框架。
5、spring事务
6、核心容器(Core Container)
获取bean的过程主要是第一第二步。
1 ApplicationContext context = new ClassPathXmlApplicationContext("hello.xml"); 2 HelloBean helloBean = (HelloBean) context.getBean("hello"); 3 helloBean.sayHello();
1、Beans:Bean工厂,bean的创建和管理。首先下面两张图:
创建bean的时序图
图(1)
创建bean的入口类是applicationCoontext,refresh()方法中有个obtainFreshBeanFactory方法是创建beanFactory的核心,然后调用AbstractRfreshAbleApplicationContext中的refreshBeanFactory(),如果已经建立了BeanFactory,则销毁并关闭该BeanFactory 。如果没有则开始创建BeanFactory。使用的是DeafultBeanFactory中的loanBeanDefinition:首先初始化了BeanDefinitionReader,加载resource(xml)定位,将xml文件转换成Document(document读取xml文件)。然后RegisterBeanDefinition将Document解析成BeanDefinition(class文件)(将bean的一些描述信息抽象成对象)具体过程建图(2)。
解析和注册bean时序图
图(2)
第一步读取xml文件将bean解析组装成beanDefiniationMap。第二步,BeanDefinition建立好bean后,就是获取bean,使用AbstractBeanFactory里getBean方法,对于所有获取Bean对象是实例,都是用这个getBean(通过反射将class反射成空对象)方法,这个方法最终调用的是doGetBean(注入值)方法,这个方法就是所谓的DI(依赖注入)发生的地方。主要是解析BeanDefinition的数据合成bean。
2、组件介绍
BeanFactory:
BeanFactory的直接子接口有3个:ListableBeanFactory(可列的)、HierarchicalBeanFactory 和 AutowireCapableBeanFactory(自动装载的)ConfigurableBeanfactory(根据配置信息的)。从上图中我们可以发现最终的默认实现类是 DefaultListableBeanFactory,他实现了所有的接口。BeanFactory、ListableBeanFactory、HierarchicalBeanFactory 和 AutowireCapableBeanFactory这四个接口共同定义了Bean的集合、Bean之间的关系、以及Bean 行为。
那为何要定义这么多层次的接口呢?最后一个类DefaultListableBeanFactory实现了所有的接口,每个单一的接口都实现了不同的功能,最后一个类继承了所有的接口,就可以实现丰富的功能。
BeanDefinition:
BeanDefinition完整描述了在Spring的配置文件中定义的<bean/>节点中所有的信息,包括各种子节点。当Spring成功解析了一个<bean/>节点后,在 Spring内部就将它被转化成BeanDefinition对象,以后所有的操作都是对这个对象完成的。
BeanDefinitionReader:
BeanDefinitionReader读入resource信息(xml)。
BeanFactoryPostProcessor:
从BeanFactoryPostProcessor 接口的名称上可以得知,实现此接口的Bean,可以在BeanFactory完成依赖注入后进行一些后继处理动作,要作什么动作取决于您,例如我们就可以在BeanFactory完成依赖注入后,根据我们提供的一个简单属性文件来设定一些经常变动的选项
Core:核心工具类
Context:运行时spring容器,上下文。
Context 在 Spring 的 org.springframework.context 包下,前面已经讲解了 Context 组件在 Spring 中的作用,他实际上就是给 Spring 提供一个运行时的环境,用以保存各个对象的状态。下面看一下这个环境是如何构建的。
总体来说 ApplicationContext 必须要完成以下几件事:
- 标识一个应用环境
- 利用 BeanFactory 创建 Bean 对象
- 保存对象关系表
- 能够捕获各种事件