Spring笔记

Spring

简介

优点:

  • 开源的免费框架

  • 轻量级非侵入式的框架

  • IOC和AOP

  • 支持事务的处理,对框架整合的支持

Spring就是一个轻量级的控制反转IOC和面向切面编程AOP的框架

控制反转IOC是一种设计思想,DI是实现IOC的一种方法

Spring Bean

Spring Bean的生命周期

Bean 生命周期的整个执行过程描述如下。

1)根据配置情况调用 Bean 构造方法或工厂方法实例化 Bean。

2)利用依赖注入完成 Bean 中所有属性值的配置注入。

3)如果 Bean 实现了 BeanNameAware 接口,则 Spring 调用 Bean 的 setBeanName() 方法传入当前 Bean 的 id 值。

4)如果 Bean 实现了 BeanFactoryAware 接口,则 Spring 调用 setBeanFactory() 方法传入当前工厂实例的引用。

5)如果 Bean 实现了 ApplicationContextAware 接口,则 Spring 调用 setApplicationContext() 方法传入当前 ApplicationContext 实例的引用。

6)如果 BeanPostProcessor 和 Bean 关联,则 Spring 将调用该接口的预初始化方法 postProcessBeforeInitialzation() 对 Bean 进行加工操作,此处非常重要,Spring 的 AOP 就是利用它实现的。

7)如果 Bean 实现了 InitializingBean 接口,则 Spring 将调用 afterPropertiesSet() 方法。

8)如果在配置文件中通过 init-method 属性指定了初始化方法,则调用该初始化方法。

9)如果 BeanPostProcessor 和 Bean 关联,则 Spring 将调用该接口的初始化方法 postProcessAfterInitialization()。此时,Bean 已经可以被应用系统使用了。

10)如果在 <bean> 中指定了该 Bean 的作用范围为 scope="singleton",则将该 Bean 放入 Spring IoC 的缓存池中,将触发 Spring 对该 Bean 的生命周期管理;如果在 <bean> 中指定了该 Bean 的作用范围为 scope="prototype",则将该 Bean 交给调用者,调用者管理该 Bean 的生命周期,Spring 不再管理该 Bean。

11)如果 Bean 实现了 DisposableBean 接口,则 Spring 会调用 destory() 方法将 Spring 中的 Bean 销毁;如果在配置文件中通过 destory-method 属性指定了 Bean 的销毁方法,则 Spring 将调用该方法对 Bean 进行销毁。

依赖注入

依赖注入(Dependency Injection,DI)和控制反转含义相同,它们是从两个角度描述的同一个概念。

当某个 Java 实例需要另一个 Java 实例时,传统的方法是由调用者创建被调用者的实例(例如,使用 new 关键字获得被调用者实例),而使用 Spring框架后,被调用者的实例不再由调用者创建,而是由 Spring 容器创建,这称为控制反转。

Spring 容器在创建被调用者的实例时,会自动将调用者需要的对象实例注入给调用者,这样,调用者通过 Spring 容器获得被调用者实例,这称为依赖注入。

依赖注入主要有两种实现方式,分别是属性 setter 注入和构造方法注入。具体介绍如下。

1)属性 setter 注入

指 IoC 容器使用 setter 方法注入被依赖的实例。通过调用无参构造器或无参 static 工厂方法实例化 bean 后,调用该 bean 的 setter 方法,即可实现基于 setter 的 DI。

2)构造方法注入

指 IoC 容器使用构造方法注入被依赖的实例。基于构造器的 DI 通过调用带参数的构造方法实现,每个参数代表一个依赖。

作用域的种类

Spring 容器在初始化一个 Bean 的实例时,同时会指定该实例的作用域。Spring3 为 Bean 定义了五种作用域,具体如下。

1)singleton

单例模式,使用 singleton 定义的 Bean 在 Spring 容器中只有一个实例,这也是 Bean 默认的作用域。

2)prototype

原型模式,每次通过 Spring 容器获取 prototype 定义的 Bean 时,容器都将创建一个新的 Bean 实例。

3)request

在一次 HTTP 请求中,容器会返回该 Bean 的同一个实例。而对不同的 HTTP 请求,会返回不同的实例,该作用域仅在当前 HTTP Request 内有效。

4)session

在一次 HTTP Session 中,容器会返回该 Bean 的同一个实例。而对不同的 HTTP 请求,会返回不同的实例,该作用域仅在当前 HTTP Session 内有效。

5)global Session

在一个全局的 HTTP Session 中,容器会返回该 Bean 的同一个实例。该作用域仅在使用 portlet context 时有效。

Spring基于Annotation装配Bean

1)@Component

可以使用此注解描述 Spring 中的 Bean,但它是一个泛化的概念,仅仅表示一个组件(Bean),并且可以作用在任何层次。使用时只需将该注解标注在相应类上即可。

2)@Repository

用于将数据访问层(DAO层)的类标识为 Spring 中的 Bean,其功能与 @Component 相同。

3)@Service

通常作用在业务层(Service 层),用于将业务层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。

4)@Controller

通常作用在控制层(如Struts2的 Action),用于将控制层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。

5)@Autowired

用于对 Bean 的属性变量、属性的 Set 方法及构造函数进行标注,配合对应的注解处理器完成 Bean 的自动配置工作。默认按照 Bean 的类型进行装配。

6)@Resource

其作用与 Autowired 一样。其区别在于 @Autowired 默认按照 Bean 类型装配,而 @Resource 默认按照 Bean 实例名称进行装配。

@Resource 中有两个重要属性:name 和 type。

Spring 将 name 属性解析为 Bean 实例名称,type 属性解析为 Bean 实例类型。如果指定 name 属性,则按实例名称进行装配;如果指定 type 属性,则按 Bean 类型进行装配。

如果都不指定,则先按 Bean 实例名称装配,如果不能匹配,则再按照 Bean 类型进行装配;如果都无法匹配,则抛出 NoSuchBeanDefinitionException 异常。

7)@Qualifier

与 @Autowired 注解配合使用,会将默认的按 Bean 类型装配修改为按 Bean 的实例名称装配,Bean 的实例名称由 @Qualifier 注解的参数指定。

Bean的自动装配

名称说明
byName 根据 Property 的 name 自动装配,如果一个 Bean 的 name 和另一个 Bean 中的 Property 的 name 相同,则自动装配这个 Bean 到 Property 中。
byType 根据 Property 的数据类型(Type)自动装配,如果一个 Bean 的数据类型兼容另一个 Bean 中 Property 的数据类型,则自动装配。
constructor 根据构造方法的参数的数据类型,进行 byType 模式的自动装配。
autodetect 如果发现默认的构造方法,则用 constructor 模式,否则用 byType 模式。
no 默认情况下,不使用自动装配,Bean 依赖必须通过 ref 元素定义。

Spring AOP

为什么需要AOP

AOP(Aspect Orient Programming)也就是面向切面编程,作为面向对象编程的一种补充,已经成为一种比较成熟的编程方式。其实AOP问世的时间并不太长,AOP和OOP互为补充,面向切面编程将程序运行过程分解成各个切面。

AOP专门用于处理系统中分布于各个模块(不同方法)中的交叉关注点的问题,在JavaEE应用中,常常通过AOP来处理一些具有横切性质的系统级服务,如事务管理、安全检查、缓存、对象池管理等,AOP已经成为一种非常常用的解决方案。

面向切面知识

名称说明
Joinpoint(连接点) 指那些被拦截到的点,在 Spring 中,可以被动态代理拦截目标类的方法。
Pointcut(切入点) 指要对哪些 Joinpoint 进行拦截,即被拦截的连接点。
Advice(通知) 指拦截到 Joinpoint 之后要做的事情,即对切入点增强的内容。
Target(目标) 指代理的目标对象。
Weaving(植入) 指把增强代码应用到目标上,生成代理对象的过程。
Proxy(代理) 指生成的代理对象。
Aspect(切面) 切入点和通知的结合。

Spring的AOP支持

Spring中的AOP代理由Spring的IoC容器负责生成、管理,其依赖关系也由IoC容器负责管理。 为了在应用中使用@AspectJ支持,Spring需要添加三个库:

  • aspectjweaver.jar

  • aspectjrt.jar

  • aopalliance.jar

并在Spring配置文件中做如下配置:

<!--启动@AspectJ支持-->
<aop:aspectj-autoproxy/>

<!--指定自动搜索Bean组件、自动搜索切面类-->
<context:component-scan base-package="edu.shu.sprint.service">
  <context:include-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect"/>
</context:component-scan>

ProxyFactoryBean

    <!--生成代理对象 -->
   <bean id="customerDaoProxy"
    class="org.springframework.aop.framework.ProxyFactoryBean">
    <!--代理实现的接口 -->
       <property name="proxyInterfaces" value="com.mengma.dao.CustomerDao" />
       <!--代理的目标对象 -->
       <property name="target" ref="customerDao" />
       <!--用通知增强目标 -->
       <property name="interceptorNames" value="myAspect" />
       <!-- 如何生成代理,true:使用cglib; false :使用jdk动态代理 -->
       <property name="proxyTargetClass" value="true" />
   </bean>

AspectJ

使用 AspectJ 开发 AOP 通常有两种方式:

  • 基于 XML 的声明式。

  • 基于 Annotation 的声明式。

<!--AOP 编程 -->
   <aop:config>
       <aop:aspect ref="myAspect">
           <!-- 配置切入点,通知最后增强哪些方法 -->
           <aop:pointcut expression="execution ( * com.mengma.dao.*.* (..))"
               id="myPointCut" />
           <!--前置通知,关联通知 Advice和切入点PointCut -->
           <aop:before method="myBefore" pointeut-ref="myPointCut" />
           <!--后置通知,在方法返回之后执行,就可以获得返回值returning 属性 -->
           <aop:after-returning method="myAfterReturning"
               pointcut-ref="myPointCut" returning="returnVal" />
           <!--环绕通知 -->
           <aop:around method="myAround" pointcut-ref="myPointCut" />
           <!--抛出通知:用于处理程序发生异常,可以接收当前方法产生的异常 -->
           <!-- *注意:如果程序没有异常,则不会执行增强 -->
           <!-- * throwing属性:用于设置通知第二个参数的名称,类型Throwable -->
           <aop:after-throwing method="myAfterThrowing"
               pointcut-ref="myPointCut" throwing="e" />
           <!--最终通知:无论程序发生任何事情,都将执行 -->
           <aop:after method="myAfter" pointcut-ref="myPointCut" />
       </aop:aspect>
   </aop:config>

Spring 事务

在 Spring 中,除了使用基于 XML 的方式可以实现声明式事务管理以外,还可以通过 Annotation 注解的方式实现声明式事务管理。

使用 Annotation 的方式非常简单,只需要在项目中做两件事,具体如下。

1)在 Spring 容器中注册驱动,代码如下所示:

<tx:annotation-driven transaction-manager="txManager"/>

2)在需要使用事务的业务类或者方法中添加注解 @Transactional,并配置 @Transactional 的参数。

整合Mybatis

<!-- mybatis -->
   <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
       <property name="dataSource" ref="dataSource" />
       <property name="configLocation" value="classpath:mybatis/mybatis-config.xml" />
       <property name="mapperLocations" value="classpath:mybatis/mapper/*.xml" />
   </bean>
   <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
       <property name="basePackage" value="com.cff.springwork.mybatis.mapper" />
   </bean>

 

问题

  1. Bean的生命周期有哪些?

    1.1 解析类得到BeanDefiniton

    1.2 如果有多个构造方法,要推断构造方法

    1.3 实例化得到一个对象

    1.4 堆对象中加了@Autowired注解的属性进行属性填充

    1.5 回调Aware方法

    1.6 调用BeanPostProcessor的初始化前的方法

    1.7 调用初始化方法

    1.8 调用BeanPostProcessor的初始化后的方法,在这里会进行AOP

    1.9 如果当前创建的Bean是单例则会把Bean放入单例池

    1.10 使用bean

    1.11 Spring容器关闭时调用DisposableBean中的destory()方法

  2. 什么是BeanDefinition?

  3. Bean的后置处理器与Bean工厂的后置处理器?

  4. BeanFactory和ApplicationContext有什么区别?

    ApplicationContext是BeanFactory的子接口

  5. 谈谈你对Spring的认识

  6. 谈谈你对Spring中IOC和AOP的理解

  7. Spring MVC设计原理

  8. 循环依赖和二级缓存的处理

posted @ 2021-07-21 22:01  洗碗君  阅读(52)  评论(0编辑  收藏  举报