爱代码

做一个最单纯的人 || 走一段最幸福的路

    已关注
    关注我

粉丝: 2 关注: 1

微信公众号搜索 未来技术网 关注我们 支付宝首页搜索:“ 7151684 ” 即可领取最高99元红包

spring框架底层(1)

  2018-05-15 09:46     30

一. 什么是Spring?

答:Spring的核心是一个轻量级的容器(Container),它是实现IoC(Inversion of Control)容器和非侵入性(No intrusive)的框架,并提供AOP(Aspect-oriented Programming)的实现方式,提供对持久层(Persistence)、事务(Transcation)的支持;提供MVC Web框架的实现,并对一些常用的企业服务API提供了一致的模型封装,是一个全方位的应用程序框架,除此之外,对现存的各种框架(Structs、JSF、Hibernate、Ibatis、Webwork等),Spring也提供了与他们相整合的方案。 
细化: 
1、Spring的核心是一个轻量级(Lightweight)的容器(Container)。 
2、Spring是实现IoC(Inversion of Control)容器和非入侵性(No intrusive)的框架。 
3、Spring提供AOP(Aspect-oriented programming)的实现方式,把应用业务逻辑和系统服务分开。 
4、Spring提供对持久层(Persistence)、事物(Transcation)的支持。 
5、Spring供MVC Web框架的实现,并对一些常用的企业服务API(Application Interface)提供一致的模型封装。 
6、Spring提供了对现存的各种框架(Structs、JSF、Hibernate、Ibatis、Webwork等)相整合的方案。 
总之,Spring是一个全方位的应用程序框架。

二、Spring的核心

1、IoC/DI(控制反转/依赖注入): 
1)控制反转可以分开来解读,控制和反转-> 首先控制什么?对什么进行控制? 其实此处的控制指的是程序中的一些对象或者变量的控制权,在传统的程序中都是由应用程序自己控制对象创建或者变量赋值,这是一种主动式的控制,导致组件之间的完全耦合;现在将一些对象或者变量的创建控制权交给一个叫做Ioc容器的东西,由这个容器来控制应用程序中所需要的资源,这样就变成了被动的控制,对组件之间的关系进行解耦,所以所谓的反转就是将控制权由应用程序转交到Ioc容器。 
2)依赖注入:同样将DI分开来解读,依赖和注入-> 首先依赖什么?谁依赖谁? 其实应用程序中所需要的资源创建和获取都是要依赖于Ioc容器,需要IoC容器装配类之间的关系,即应用程序依赖于IoC容器的装配功能;相反,注入就是IoC容器向应用程序中进行注入应用程序所需要的资源,由应用程序主动装配对象的依赖变应用程序被动接受依赖,所以IoC容器也叫DI容器。

综上所述,控制权的主动与被动式其实都是相对于(参考物)IoC容器来说的,也可以将IoC模式看做是工厂模式的升华,不同的是Spring中的控制反转所用到的是Java的“反射”技术,通过在XML文件中定义应用程序所需要的类,再由IoC容器根据xml文件创建这些对象。所以这也形成了工厂与对象生成这两者独立分隔开,目的就是提高灵活性和可维护性。之所以将对象生成放到xml文件中,如果我们想要换一个实现的类将变得很简单,只需要修改xml文件即可。 
2、AOP(面向切面编程):将具体的通用的应用从业务逻辑中分离出来,各自做各自专业的事情。 
1)切面:简单的理解就是一个类,每个或者对象 
2)连接点:类中的方法(可以切入的地方) 
3)通知:切面在某个连接点执行的操作(分为: Before advice , After returning advice , After throwing advice , After (finally) advice , Around advice ); 
4)切入点:符合切点表达式的连接点,也就是真正被切入的地方 
5)引入: 
6)目标对象:

三、Spring能做什么?

四、Spring注入Bean的方式

(1)设值注入(set方法) 
(2)构造器注入 
(3)工厂方法 
Spring加载Bean的流程: 
(1)创建一个上下文context = createApplicationContext; 
(2)context中都会有一个BeanFactory(默认是DefaultListableBeanFactory),在该类的子类类xmlBeanFactory中进行xml文件的解析; 
(3)在类XmlBeanDefinitionParser 中用Dom解析xml文件(DefaultXmlBeanDefinitionParser),解析xml文件中所有bean,并将bean放到BeanDefinitionHolder中,封装成BeanDefinition; 
(4)再进行bean的注册,具体在BeanDefinitionReaderUtils类调用DefaultListableBeanFactory类的registerBeanDefinition进行bean的注册,在这里用了一HashMap存放bean,其中用Beanname作为键值,其封装好的beanDefinition作为值。还有用一个List存放所有的bean的名字。

设值注入和构造器注入的区别

1) 在设置注入需要该Bean包含这些属性的setter方法; 
2) 与传统的JavaBean的写法更相似,程序开发人员更容易理解、接收。通过setter方法设定依赖关系显得更加只管; 
3) 对于复杂的依赖关系,如果采用构造注入,会导致构造器参数列表复杂,难以阅读。Spring在创建Bean实例时,需要同时实例化其它依赖的全部实例,因而导致性能下降。而使用设值注入,则能避免这些问题; 
4) 尤其是在某些属性可选的情况况下,多参数的构造器显得更加复杂; 
但是在其他的场景,构造器注入显得更好的性能: 
1) 构造注入需要该Bean包含带有这些属性的构造器; 
2) 构造注入可以在构造器中决定依赖关系的注入顺序,优先依赖的优先注入; 
3) 对于依赖关系无需变化的Bean,构造注入更有用处。因为没有Setter方法,所有的依赖关系全部在构造器内设定。因此,无需担心后续的代码对依赖关系产生破坏 
4) 依赖关系只能在构造器中设定,则只有组件的创建者才能改变组件的依赖关系。对组件的调用者而言,组件内部的依赖关系完全透明,更符合高内聚的原则.

(1)在使用设值注入时有可能还不能保证某种依赖是否已经被注入,也就是说这时对象的依赖关系有可能是不完整的。而在另一种情况下,构造器注入则不允许生成依赖关系不完整的对象。 
(2)在设值注入时如果对象A和对象B互相依赖,在创建对象A时Spring会抛出sObjectCurrentlyInCreationException异常,因为在B对象被创建之前A对象是不能被创建的,反之亦然。所以Spring用设值注入的方法解决了循环依赖的问题,因对象的设值方法是在对象被创建之前被调用的。

注:采用以设值注入为主,构造注入为辅的注入策略。对于依赖关系无需变化的注入,尽量采用构造注入;而其他的依赖关系的注入,则考虑采用设值注入。

五、Bean的生命周期(以BeanFactory)

1) Bean的建立,由BeanFactory读取Bean定义文件,并创建Bean实例; 
2) 执行Bean的属性注入,Setter注入; 
3) 如果Bean类实现了org.springframework.beans.factory.BeanNameAware接口,则执行其setBeanName方法; 
4) 如果Bean类实现了org.springframework.beans.factory.BeanFactoryAware接口,则执行其setBeanFactory方法; 
5) 如果容器中有实现org.springframework.beans.factory.BeanPostProcessors接口的实例,则任何Bean在初始化之前都会执行这个实例的processBeforeInitialization()方法; 
6) 如果Bean类实现了org.springframework.beans.factory.InitializingBean接口,则执行其afterPropertiesSet()方法; 
7) 调用Bean的初始化方法”init-method” (!!注意,init-method方法没有参数); 
8) 如果容器中有实现org.springframework.beans.factory.BeanPostProcessors接口的实例,则任何Bean在初始化之后都会执行这个实例的processAfterInitialization()方法; 
9) 使用Bean做一些业务逻辑…. 
10) 使用完,容器关闭,如果Bean类实现了org.springframework.beans.factory.DisposableBean接口,则执行它的destroy()方法; 
11) 在容器关闭时,可以在Bean定义文件中使用“destory-method”定义的方法,销毁Bean (!!注意,destory-method方法没有参数);

ApplicationContext中bean的生命周期也是类似的。

六、BeanFactory 和ApplicationContext的区别

  1. 首先BeanFactory和ApplicationContext都是接口,并且ApplicationContext是BeanFactory的子接口。

  2. 其次BeanFactory是Spring中最底层的接口,提供了最简单的容器的功能,只提供了实例化对象和拿对象的功能, 
    ApplicationContext(应用上下文)它是Spring的一个更高级的容器,提供了更多的有用的功能; 
    1)ApplicationContext继承了BeanFactory接口,所以,ApplicationContext也能像BeanFactory从容器中得到Bean(继承至 ListableBeanFactory); 
    2)ApplicationContext提供的额外的功能: 
    国际化的功能,消息发送、响应机制(继承至MessageSource );统一加载资源的功能(继承至ResourceLoader);强大的事件机制( 继承至ApplicationEventPublisher);对Web应用的支持()

  3. 它们的加载方式不同: 
    1) BeanFactory采用的是延迟加载的形式来注入Bean,即只有在使用某个bean的时候,才对该Bean进行加载实例化.好处是节约内存,缺点是速度比较慢. 
    2) ApplicationContext则相反的,它是在Ioc容易启动时就一次性创建所有的Bean,这样的好处是可以马上发现Spring配置文件中的错误。坏处就是浪费内存。

ApplicationContext的三种较常见的实现方式: 
1) ClassPathXmlApplicationContext:从classpath的xml配置文件中读取上下文,并生成上下文定义,应用程序上下文从程序环境中取得。

ApplicationContext context = new ClassPathXmlApplicationContext("****.xml");1

2) FileSystemXmlApplicationContext:由文件系统中的xml配置文件读取上下文。

ApplicationContext context = new FileSystemXmlApplicationContext("****.xml");1

3) XmlWebApplicationContext:由Web应用的Xml文件读取上下文。

七、Spring Bean的作用域

1) Singleton: 这是默认的作用域,这种范围确保不管接受多少个请求,每个容器中只有一个bean的实例,单例模式有BeanFactory自身维护; 
2) Prototype: 原形范围与单例范围相反,为每一个bean请求提供一个实例; 
3) Request: 在请求bean范围内会为每一个来自客户端的网络请求创建一个实例,在请求完成以后,bean会失效并被垃圾回收器回收; 
4) Session: 与请求范围类似,确保每个session中有一个bean的实例,在session过期后,bean会随之失效; 
5) global-session: global-session和Portlet应用相关。当你的应用部署在Portlet容器中工作时,它包含很多portlet。如果你想要声明让所有的portlet共用全局的存储变量的话,那么这全局变量需要存储在global-session中。

八、Bean的自动装配模式

  1. no: spring默认的设置,在该设置下自动装配是关闭的,开发者需要在配置文件中用标签明确依赖关系;

  2. byName: 该选项可以根据bean名称设置依赖关系。当向一个bean中自动装配一个属性时,容器将根据bean的名称自动在在配置文件中查询一个匹配的bean。如果找到的话,就装配这个属性,如果没找到的话就报错。

  3. byType: 该选项可以根据bean类型设置依赖关系。当向一个bean中自动装配一个属性时,容器将根据bean的类型自动在在配置文件中查询一个匹配的bean。如果找到的话,就装配这个属性,如果没找到的话就报错。

  4. constructor: 构造器自动装载,仅仅适用于与有构造器相同参数的bean,如果在容器中没有找到与构造器参数类型一致的bean,那么将会抛出异常。

  5. autodetect: 该模式自动探测使用构造器自动装配或者byType自动装配。先尝试找合适的带参数的构造函数,若没有则自动选择byType的自动装配模式。

基于注解的自动装配,spring默认是关闭注解模式的,所以需要在配置文件中设置

九、各种注解的解释

  1. @Required: 验证bean是否被正确的设置了,需要在Ioc容器中注册RequiredAnnotationBeanPostProcessor,它是Spring中的后置处理用来验证被@Required 注解的bean属性是否被正确的设置了,若没有属性被@Required注解过的话,后置处理器会抛出一个BeanInitializationException异常。 

  2. @AutoWired: 该注解用于在bean的设值方法上自动装配bean的属性,一个参数或者带有任意名称或带有多个参数的方法。(尝试用byType 自动装配)

  3. @Qualifer: 该注解一般和@AutoWired一起使用,用于帮助Ioc容器能知道当前注解的属性应该自动装配哪一个。(对于在xml文件中定义了多个同类的bean,但是id不同,若单单用@AutoWired进行注解,Ioc容器无法分辨出应该自动装配哪一个bean)

十、Spring 中的所有哪些不同类型的事件?

Spring的ApplicationContext提供了支持事务和代码中添加监听器的功能。 
可以创建一个bean其实现ApplicationListener接口(类型是ApplicationEvent),当一个ApplicationEvent 被发布后,bean就自动被通知,并且在方法onApplicationEvent(…)方法中处理该事件。

public class AllApplicationEventListener implements ApplicationListener < ApplicationEvent >
{
    @Override    public void onApplicationEvent(ApplicationEvent applicationEvent)
    {        //process event
    }
}12345678

在Spring中有5中标准的事件: 
1. 上下文更新事件(ContextRefreshedEvent):该事件会在ApplicationContext被初始化或者更新时发布,也可以在调用ConfigurableApplicationContext接口中的refresh()方法时被触发。 
2. 上下文开始事件(ContextStartedEvent): 当容器调用ConfigurableApplicationContext的Start()方法开始/重新开始容器时被触发。 
3. 上下文停止事件(ContextStoppedEvent): 当容器调用ConfigurableApplicationContext的Stop()方法停止容器时触发该事件。 
4. 上下文关闭事件(ContextClosedEvent): 当ApplicationContext被关闭时触发该事件。容器被关闭时,其管理的所有单例Bean都被销毁。 
5. 请求处理事件(RequestHandledEvent): 在Web应用中,当一个http请求(request)结束触发该事件。

spring也让用户可以自定义事件类型,继承ApplicationEvent。

public class CustomApplicationEvent extends ApplicationEvent{
    public CustomApplicationEvent ( Object source, final String msg )
    {        super(source);
        System.out.println("Created a Custom event");
    }
}12345678

为了监听这个事件,还需要创建一个监听器:

public class CustomEventListener implements ApplicationListener < CustomApplicationEvent >
{
    @Override    public void onApplicationEvent(CustomApplicationEvent applicationEvent) {        //handle event
    }
}1234567

之后通过applicationContext接口的publishEvent()方法来发布自定义事件。

CustomApplicationEvent customEvent = new CustomApplicationEvent(applicationContext, "Test message");
applicationContext.publishEvent(customEvent);12

十一、Spring 框架中都用到了哪些设计模式?

  1. 代理模式—在AOP和remoting中被用的比较多。

  2. 单例模式—在spring配置文件中定义的bean默认为单例模式。

  3. 模板方法—用来解决代码重复的问题。比如. RestTemplate, JmsTemplate, JpaTemplate。

  4. 前端控制器—Spring提供了DispatcherServlet来对请求进行分发。

  5. 视图帮助(View Helper )—Spring提供了一系列的JSP标签,高效宏来辅助将分散的代码整合在视图里。

  6. 依赖注入—贯穿于BeanFactory / ApplicationContext接口的核心理念。

  7. 工厂模式—BeanFactory用来创建对象的实例。


查看评论
发表评论
官方公众号