Spring的原理性总结

一、Bean的生命过程

Bean的生命过程可以借鉴Servlet的生命过程,了解其生命过程对于不管是思想还是以后的使用都很有帮助;

Bean可以通过两种方式进行加载,分别是使用BeanFactory 和 applicationContext, 下边就这两种方式进行Bean的声明周期总结:

applicationContext:

先用一种生命周期流程图来概括;

1:Bean的建立:

容器寻找Bean的定义信息并将其实例化,也就是new一个对象,。

2:属性注入:

使用依赖注入,Spring按照Bean定义信息配置Bean所有属性,相当于调用set方法进行属性set操作

3. 如果这个Bean实现了BeanNameAware接口,会调用它实现的setBeanName(String beanId)方法,此处传递的是Spring配置文件中Bean的ID

4. 如果这个Bean实现了BeanFactoryAware接口,会调用它实现的setBeanFactory(),传递的是Spring工厂本身(可以用这个方法获取到其他Bean)

5. 如果这个Bean实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文,该方式同样可以实现步骤4,但比4更好,以为ApplicationContext是BeanFactory的子接口,有更多的实现方法

6. 如果这个Bean关联了BeanPostProcessor接口,将会调用postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor经常被用作是Bean内容的更改,并且由于这个是在Bean初始化结束时调用After方法,也可用于内存或缓存技术

7.如果设置了initializingBean接口,则会调用实现的afterPropertiesSet()方法;

8. 如果这个Bean在Spring配置文件中配置了init-method属性会自动调用其配置的初始化方法【相当于定制方法】

9. 如果这个Bean关联了BeanPostProcessor接口,将会调用postAfterInitialization(Object obj, String s)方法

注意:以上工作完成以后就可以用这个Bean了,那这个Bean是一个single的,所以一般情况下我们调用同一个ID的Bean会是在内容地址相同的实例

10. 容器关闭,当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean接口,会调用其实现的destroy方法,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法

BeanFactory:

下边对BeanFactory的生命周期过程进行分析,BeanFactory的生命周期相对于ApplicationContext来说相对简化了一些;

下面用图进行概括:

下面以BeanFactory为例,说明一个Bean的生命周期活动

  • Bean的建立, 由BeanFactory读取Bean定义文件,并生成各个实例
  • Setter注入,执行Bean的属性依赖注入
  • BeanNameAware的setBeanName(), 如果实现该接口,则执行其setBeanName方法
  • BeanFactoryAware的setBeanFactory(),如果实现该接口,则执行其setBeanFactory方法
  • InitializingBean的afterPropertiesSet(),如果实现了该接口,则执行其afterPropertiesSet()方法
  • Bean定义文件中定义init-method
  • DisposableBean的destroy(),在容器关闭时,如果Bean类实现了该接口,则执行它的destroy()方法
  • Bean定义文件中定义destroy-method,在容器关闭时,可以在Bean定义文件中使用“destory-method”定义的方法

如果使用ApplicationContext来维护一个Bean的生命周期,则基本上与上边的流程相同,只不过在执行BeanNameAware的setBeanName()后,若有Bean类实现了org.springframework.context.ApplicationContextAware接口,则执行其setApplicationContext()方法,然后再进行BeanPostProcessors的processBeforeInitialization() 实际上,ApplicationContext除了向BeanFactory那样维护容器外,还提供了更加丰富的框架功能,如Bean的消息,事件处理机制等

 结果展示:

二、BeanFactory 接口和 ApplicationContext 接口有什么区别 ?

    ①ApplicationContext 接口继承BeanFactory接口,Spring核心工厂是BeanFactory ,BeanFactory采取延迟加载,第一次getBean时才会初始化Bean, ApplicationContext是会在加载配置文件时初始化Bean。

    ②ApplicationContext是对BeanFactory扩展,它可以进行国际化处理、事件传递和bean自动装配以及各种不同应用层的Context实现 

开发中基本都在使用ApplicationContext, web项目使用WebApplicationContext ,很少用到BeanFactory

BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
IHelloService helloService = (IHelloService) beanFactory.getBean("helloService");
helloService.sayHello();

三、Bean的加载方式:

   1)使用类构造器实例化(默认无参数)

 <bean id="bean1" class="cn.itcast.spring.b_instance.Bean1"></bean>

    2)使用静态工厂方法实例化(简单工厂模式)

//下面这段配置的含义:调用Bean2Factory的getBean2方法得到bean2
<bean id="bean2" class="cn.itcast.spring.b_instance.Bean2Factory" factory-method="getBean2"></bean>

    3)使用实例工厂方法实例化(工厂方法模式)

//先创建工厂实例bean3Facory,再通过工厂实例创建目标bean实例
<bean id="bean3Factory" class="cn.itcast.spring.b_instance.Bean3Factory"></bean>
<bean id="bean3" factory-bean="bean3Factory" factory-method="getBean3"></bean>

四、请介绍一下Spring框架中Bean的生命周期和作用域

(1)bean定义

    在配置文件里面用<bean></bean>来进行定义。

(2)bean初始化

    有两种方式初始化:

A.在配置文件中通过指定init-method属性来完成

B.实现org.springframwork.beans.factory.InitializingBean接口

(3)bean调用

    有三种方式可以得到bean实例,并进行调用

(4)bean销毁

    销毁有两种方式

A.使用配置文件指定的destroy-method属性

B.实现org.springframwork.bean.factory.DisposeableBean接口

##作用域

singleton

当一个bean的作用域为singleton, 那么Spring IoC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。

prototype

Prototype作用域的bean会导致在每次对该bean请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean() 方法)时都会创建一个新的bean实例。根据经验,对所有有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用 singleton作用域

request

在一次HTTP请求中,一个bean定义对应一个实例;即每次HTTP请求将会有各自的bean实例, 它们依据某个bean定义创建而成。该作用 域仅在基于web的Spring ApplicationContext情形下有效。

session

在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。

global session

在一个全局的HTTP Session中,一个bean定义对应一个实例。典型情况下,仅在使用portlet context的时候有效。该作用域仅在基于 web的Spring ApplicationContext情形下有效。

五、Bean注入属性有哪几种方式?

spring支持构造器注入和setter方法注入

    构造器注入,通过 <constructor-arg> 元素完成注入

    setter方法注入, 通过<property> 元素完成注入【开发中常用方式】

六、Spring的核心类有哪些,各有什么作用?

BeanFactory:产生一个新的实例,可以实现单例模式

BeanWrapper:提供统一的get及set方法

ApplicationContext:提供框架的实现,包括BeanFactory的所有功能

七、Spring里面如何配置数据库驱动?

使用”

com.mchange.v2.c3p0.ComboPooledDataSource

”数据源来配置数据库驱动。示例如下:

      <!-- 配置数据库数据源 -->
      <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">      
        <property name="driverClass" value="${jdbc.driverClassName}"/>      
        <property name="jdbcUrl" value="${jdbc.url}"/>      
        <property name="user" value="${jdbc.username}"/>      
        <property name="password" value="${jdbc.password}"/>
               
        <!-- 初始化连接大小 -->
        <property name="initialPoolSize" value="${initialSize}"/>
        <!-- 最小连接池数量 -->
        <property name="minPoolSize" value="${minActive}" />
        <!-- 连接池最大数量 -->
        <property name="maxPoolSize" value="${maxActive}"/>
         <property name="autoCommitOnClose" value="true"/>
    </bean> 

八、Spring里面applicationContext.xml文件能不能改成其他文件名?

ContextLoaderListener是一个ServletContextListener, 它在你的web应用启动的时候初始化。缺省情况下, 它会在WEB-INF/applicationContext.xml文件找Spring的配置。

你可以通过定义一个<context-param>元素名字为”contextConfigLocation”来改变Spring配置文件的 位置。示例如下: 

<listener> 
    <listener-class>org.springframework.web.context.ContextLoaderListener
        <context-param> 
         <param-name>contextConfigLocation</param-name> 
         <param-value>/WEB-INF/xyz.xml</param-value> 
        </context-param>   
    </listener-class> 
</listener> 

九、Spring如何处理线程并发问题?

Spring使用ThreadLocal解决线程安全问题【博客有一节专门对于TreadLocal的分析】

我们知道在一般情况下,只有无状态的Bean才可以在多线程环境下共享,在Spring中,绝大部分Bean都可以声明为singleton作用域。就是因为Spring对一些Bean(如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等)中非线程安全状态采用ThreadLocal进行处理,让它们也成为线程安全的状态,因为有状态的Bean就可以在多线程中共享了。

ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。

在同步机制中,通过对象的锁机制保证同一时间只有一个线程访问变量。这时该变量是多个线程共享的,使用同步机制要求程序慎密地分析什么时候对变量进行读写,什么时候需要锁定某个对象,什么时候释放对象锁等繁杂的问题,程序设计和编写难度相对较大。

而ThreadLocal则从另一个角度来解决多线程的并发访问。ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。

由于ThreadLocal中可以持有任何类型的对象,低版本JDK所提供的get()返回的是Object对象,需要强制类型转换。但JDK5.0通过泛型很好的解决了这个问题,在一定程度地简化ThreadLocal的使用。

概括起来说,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。

十、为什么要有事物传播行为?

十一、介绍一下Spring的事物管理

    事务就是对一系列的数据库操作(比如插入多条数据)进行统一的提交或回滚操作,如果插入成功,那么一起成功,如果中间有一条出现异常,那么回滚之前的所有操作。这样可以防止出现脏数据,防止数据库数据出现问题。

开发中为了避免这种情况一般都会进行事务管理。Spring中也有自己的事务管理机制,一般是使用TransactionMananger进行管 理,可以通过Spring的注入来完成此功能。spring提供了几个关于事务处理的类:

TransactionDefinition //事务属性定义

TranscationStatus //代表了当前的事务,可以提交,回滚。

PlatformTransactionManager这个是spring提供的用于管理事务的基础接口,其下有一个实现的抽象类 AbstractPlatformTransactionManager,我们使用的事务管理类例如 DataSourceTransactionManager等都是这个类的子类。

一般事务定义步骤:

TransactionDefinition td =newTransactionDefinition();
TransactionStatus ts = transactionManager.getTransaction(td);
try{ 
    //do sth
    transactionManager.commit(ts);
}catch(Exception e){
    transactionManager.rollback(ts);
}

 spring提供的事务管理可以分为两类:编程式的和声明式的。

编程式的,比较灵活,但是代码量大,存在重复的代码比较多;

编程式主要使用transactionTemplate。省略了部分的提交,回滚,一系列的事务对象定义,需注入事务管理对象.【这里使用了模板模式】

void add(){
    transactionTemplate.execute(newTransactionCallback(){
        pulic Object doInTransaction(TransactionStatus ts){
         //do sth
        }
    }
}

声明式:声明式的比编程式的更灵活。

使用TransactionProxyFactoryBean:PROPAGATION_REQUIRED PROPAGATION_REQUIRED PROPAGATION_REQUIRED,readOnly

围绕Poxy的动态代理 能够自动的提交和回滚事务

org.springframework.transaction.interceptor.TransactionProxyFactoryBean

PROPAGATION_REQUIRED–支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。

PROPAGATION_SUPPORTS–支持当前事务,如果当前没有事务,就以非事务方式执行。

PROPAGATION_MANDATORY–支持当前事务,如果当前没有事务,就抛出异常。

PROPAGATION_REQUIRES_NEW–新建事务,如果当前存在事务,把当前事务挂起。

PROPAGATION_NOT_SUPPORTED–以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

PROPAGATION_NEVER–以非事务方式执行,如果当前存在事务,则抛出异常。

PROPAGATION_NESTED–如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与 PROPAGATION_REQUIRED类似的操作。

十二、AOP

1. 说出Spring的通知类型有哪些?

spring共提供了五种类型的通知:

通知类型

接口

描述

Around 环绕通知

org.aopalliance.intercept.MethodInterceptor

拦截对目标方法调用

Before 前置通知

org.springframework.aop.MethodBeforeAdvice

在目标方法调用前调用

After  后置通知

org.springframework.aop.AfterReturningAdvice

在目标方法调用后调用

Throws 异常通知

org.springframework.aop.ThrowsAdvice

当目标方法抛出异常时调用

<bean id="myMethodBeforeAdvice" class="com.cdtax.aop.MyMethodBeforeAdvice"></bean>
<!-- 配置后置通知 -->
<bean id="myAfterReturningAdvice" class="com.cdtax.aop.MyAfterReturningAdvice"></bean>
<!-- 配置代理对象 -->
<bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean"> 
<!-- 代理接口集 -->
    <property name="proxyInterfaces">
        <list>
            <value>com.cdtax.aop.TestServiceInter</value>
            <value>com.cdtax.aop.TestServiceInter2</value>
        </list>
    </property>
    
    <!-- 把通知织入到代理对象  | 拦截器名集-->
    <property name="interceptorNames">
        <list>
        <!-- 相当于把 MyMethodBeforeAdvice前置通知和代理对象关联起来,我们也可以把通知看成拦截器,struts2核心就是拦截器 -->
         <value>myMethodBeforeAdvice</value> 
                
        <!-- 织入后置通知 -->
        <value>myAfterReturningAdvice</value>
                
        </list>
    </property>
    
    <!-- 配置被代理对象,可以指定 -->
    <property name="target" ref="test1Service">
        
    </property>
</bean>
</beans>

2. 谈谈目标对象实现接口与目标对象不实现接口有什么区别?

3. 请描述JDK动态代理和CGLI代理的区别?

  jdk动态代理是目标类实现了接口,而不能针对类;

  CGLI动态代理是目标类没有实现接口。主要是对指定的类生成一个子类,覆盖其中的方法。

4. 简述ProxyFactoryBean的作用是什么?

5. 叙述Spring中的自动代理的原理?

5. 写出创建代理对象需指定的三要素是什么?

 (1)设定目标对象  (2)设定代理接口  (3)设定拦截器的名字

6. 写出代理的两种方式分别是什么?

7. 请简述:什么是AOP?简述AOP核心?

9. 请叙述AOP事务的含义?

1. 请简述Spring的工作机制?

2. 请回答你为什么用Spring的工作机制?

3. 请简述Spring是什么?

4. 简述spring的组成?

5.简述Spring容器提供了哪些功能?

6. 在Spring中,bean的注入有几种方式,各是什么?

7. 请简述:Spring bean的作用域?

8. 请叙述设值注入的优点?

9. 请叙述构造注入的优点?

10. 说出bean工厂创建bean的三种方式? 11. 请写出bean的生命周期的方法?

12. 请简述你对IOC的理解?

13. 请回答:IoC最大的好处是什么?

14. 简述IoC的类型?

15. Spring中依赖注入与传统编程之间的差别是什么?

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏LeoXu的博客

Tapestry 教程(四)探索项目结构 原

l Web应用程序文件放在 src/main/webapp(包括src/main/webapp/WEB-INF)

882
来自专栏xingoo, 一个梦想做发明家的程序员

【Spring实战】—— 16 基于JDBC持久化的事务管理

前面讲解了基于JDBC驱动的Spring的持久化管理,本篇开始则着重介绍下与事务相关的操作。 通过本文你可以了解到: 1 Spring 事务管理的机制 ...

2179
来自专栏斑斓

Spray中的Authentication和JMeter测试

Spray Authentication 在Spray中,如果需要对REST API添加认证,可以使用Spray提供的Authenticate功能。本质上,Au...

3779
来自专栏Ryan Miao

springmvc学习笔记--json--返回json的日期格式问题

(一)输出json数据 springmvc中使用jackson-mapper-asl即可进行json输出,在配置上有几点: 1.使用mvc:annotation...

47810
来自专栏WindCoder

Spring Boot REST API错误处理指南

本来是5号来的文章,无奈最近准备换工作,一直拖着没写,今天搜索偶然看见有人已经翻译完了,由于时间原因这次就直接转载下吧,现附上英文原文及相关信息,最后再附上译文...

2322
来自专栏SDNLAB

OpenDaylight Carbon二次开发实用指南

通过本文你将知道: Maven Archetype的基本原理以及如何使用Maven Archetype生成适用于不同版本的ODL子项目。 本文将着重讲解cli命...

45715
来自专栏林欣哲

单元测试JUnit4 知识点速查

JUnit4的变化 JUnit4的测试类不再需要继承测试类。 只要用了@Test注解,方法名不再需要test开头 直接IDE支持用JUnit测试。 测试用例的目...

3508
来自专栏向治洪

Widget简介

Widget简介 可以使用AppWidgetManager更新Widget中的数据,但这样最短也要半个小时才能更新一次,一般不用他更新,而是自己定义一个服务去更...

2207
来自专栏一枝花算不算浪漫

[Java面试五]Spring总结以及在面试中的一些问题.

45719
来自专栏JavaEE

Thymeleaf的使用前言:一、thymeleaf简介:二、thymeleaf标准方言:三、thymeleaf与springboot集成案例:总结:

最近听说thymeleaf好像也挺流行的,还说是spring官方推荐使用,那thymeleaf究竟是什么呢?spring为什么推荐用它呢?怎么用呢?本文将为你揭...

1442

扫码关注云+社区

领取腾讯云代金券