【java总结】框架之Spring

Spring基础

什么是Spring?

  • Spring是一个开源的免费的框架(容器)
  • Spring是一个轻量级的,非入侵式的框架
  • 两个特性:控制反转(IOC)面向切面编程(AOP)
  • 支持事务的处理,对框架整合的支持

使用Spring的好处

方便解耦——Spring提供的IoC容器实现了对象依赖关系的管理,避免了硬编码导致的耦合。

支持AOP——Spring提供的AOP功能,方便进行面向切面编程。

声明式事物——Spring提供了通过声明的方式灵活的进行事务管理。

方便程序测试——可以用非容器以来的编程方式进行几乎所有的测试工作。

集成了多种优秀框架——Spring提供了对各种优秀框架(如Struts、Hibernate、Hessian、Quartz等)的直接支持。

降低Java EE API的使用难度——Spring对很多难用的Java EE API(如JDBC、JavaMail、远程调用等)提供了一个薄薄的封装层,使得这些Java EE API的使用难度大为降低。

Java源码是经典学习范例——Spring的源码设计精妙、结构清晰,是Java技术的最佳实践的范例。

事务管理:Spring提供一个持续的事务管理接口,可以扩展到上至本地事务下至全局事务 (JTA)。

异常处理:Spring提供方便的API把具体技术相关的异常(比如由JDBC,HibernateorJDO抛 出的)转化为一致的unchecked异常。

Spring组成

image

  • 核心容器 :核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。 BeanFactory 使用 控制反转 (IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。Spring框架建立在此模块之上,它使Spring成为一个容器。

  • Spring 上下文 :Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。

  • Spring AOP :通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖 EJB 组件,就可以将声明性事务管理集成到应用程序中。

  • Spring DAO

    DAO(Data Access Object)是用于访问数据的对象,虽然在大多数情况下将数存在数据库中,但这并不是唯一的选择,也可以将数据存储到文件中或LDAP中。DAO不但屏蔽了数据存储的最终介质的不同,也屏蔽了具体的实现技术的不同。

    JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。

  • Spring ORM :Spring 框架插入了若干个 ORM 框架,支持我们在直接JDBC之上使用一个对象/关系映射映射(ORM)工具,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。

  • Spring Web 模块 :Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。

  • Spring MVC 框架 :MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。

BeanFactory和ApplicationContext有什么区别?

BeanFactory 可以理解为含有bean集合的工厂类。BeanFactory 包含了种bean的定义,以便 在接收到客户端请求时将对应的bean实例化。

最常用的BeanFactory实现是XmlBeanFactory类。

最常用的就是org.springframework.beans.factory.xml.XmlBeanFactory,它根据XML文件中的 定义加载beans。该容器从XML文件读取配置元数据并用它去创建一个完全配置的系统或应 用。

BeanFactory还能在实例化对象的时生成协作类之间的关系。此举将bean自身与bean客户端 的配置中解放出来。BeanFactory还包含 了bean生命周期的控制,调用客户端的初始化方法 (initialization methods)和销毁方法(destruction methods)。

从表面上看,application context如同bean factory一样具有bean定义、bean关联关系的设 置,根据请求分发bean的功能。但applicationcontext在此基础上还提供了其他的功能。

1.提供了支持国际化的文本消息

2.统一的资源文件读取方式

3.已在监听器中注册的bean的事件

以下是三种较常见的 ApplicationContext 实现方式:

1、ClassPathXmlApplicationContext:从classpath的XML配置文件中读取上下文,并生成上 下文定义。应用程序上下文从程序环境变量中 ApplicationContext context = new ClassPathXmlApplicationContext(“bean.xml”);

2、FileSystemXmlApplicationContext :由文件系统中的XML配置文件读取上下文。 ApplicationContext context = new FileSystemXmlApplicationContext(“bean.xml”);

3、XmlWebApplicationContext:由Web应用的XML文件读取上下文。

4.AnnotationConigApplicationContext(基于Java配置启动容器)

核心功能

IOC

控制反转IoC

IoC的字面意思是控制反转,它包括两部分的内容:

  • 控制:在上述案例中,控制就是选择套餐中汉堡和饮品的控制权。
  • 反转:反转就是把该控制权从套餐本身中移除,放到专门的服务员手中。

对于Spring来说,我们通过Spring容器管理来管理和控制Bean的装配。

依赖注入

由于IoC这个重要的概念比较晦涩隐讳,Martin Fowler提出了DI(Dependency Injection,依赖注入)的概念用以代替IoC,即让调用类对某一接口实现类的依赖关系由第三方(容器或协作类)注入,以移除调用类对某一接口实现类的依赖。

Spring的核心模块实现了IoC的功能,它将类和类之间的依赖从代码中脱离出来,用配置的方式进行依赖关系描述,由IoC容器负责类的创建,管理,获取等工作。让开发者可以从这些底层实现类的实例化、依赖关系装配等工作中解脱出来,专注于更有意义的业务逻辑开发。

BeanFactory接口是Spring框架的核心接口,实现了容器很多核心的功能。

Context模块构建于核心模块之上,扩展了BeanFactory的功能,包括国际化、Bean生命周期控制、框架事件体系、资源加载透明化等功能;还提供了众多企业级服务的支持,如邮件服务、任务调度、JNDI、EJB、远程访问等。ApplicationContext是Context模块的核心接口。

表达式语言(Expression Language)是统一表达式语言的一个扩展,用于查询和管理运行期的对象,支持设置和获取对象属性,调用对象方法,操作数组、集合等。使用它可以很方便的通过表达式和Spring IoC容器进行交互。

什么是SpringIOC容器?

SpringIOC负责创建对象,管理对象(通过依赖注入(DI),装配对象,配置对象,并且管 理这些对象的整个生命周期。

AOP

AOP(Aspect Oriented Programing)即面向切面编程,适用于那些具有横切逻辑的应用场合,是OOP的重要补充。通过 spring 的 AOP 技术,就可以在不修改 代码的情况下完成需求。

AOP有几个重要的概念:

  1. 连接点(Joinpoint):一段代码中一些具有边界性质的点,如类开始初始化前、类初始化后、方法调用前后、方法抛出异常。Spring仅支持方法的连接点。
  2. 切点(Pointcut):AOP通过切点定位连接点,相当于是连接点的定位条件。在Spring中,切点通过org.springframework.aop.Pointcut接口进行描述。
  3. 增强(Advice):增强是指在目标连接点上织入一段程序代码。
  4. 目标类(Target):织入增强逻辑的目标类。
  5. 引介(Introduction): 引介是一种特殊的增强,它为类添加一些属性和方法。这样,即使一个业务类原本没有实现某个接口,通过AOP的引介功能,我们可以动态地为该业务类添加接口的实现逻辑,让业务类成为这个接口的实现类。
  6. 织入(Weaving):是将增强添加对目标类具体连接点上的过程。根据不同的实现技术,AOP有三种织入的方式(Spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入):
    a. 编译期织入,这要求使用特殊的Java编译器。
    b. 类装载期织入,这要求使用特殊的类装载器。
    c. 动态代理织入,在运行期为目标类添加增强生成子类的方式。
  7. 代理(Proxy):一个类被AOP织入增强后,就产出了一个结果类,它是融合了原类和增强逻辑的代理类。根据不同的代理方式,代理类既可能是和原类具有相同接口的类,也可能就是原类的子类,所以我们可以采用调用原类相同的方式调用代理类。
  8. 切面(Aspect):切面由切点和增强(引介)组成,它既包括了横切逻辑的定义,也包括了连接点的定义。Spring AOP就是负责实施切面的框架,它将切面所定义的横切逻辑织入到切面所指定的连接点中。

Spring AOP 实现原理

Spring AOP 中的动态代理主要有两种方式,JDK 动态代理和 CGLIB 动态代理。JDK 动态代 理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。

概念

Spring配置文件

Spring配置文件是个XML文件,这个文件包含了类信息,描述了如何配置它们,以及如何相 互调用。

什么是SpringIOC容器?

SpringIOC负责创建对象,管理对象(通过依赖注入(DI),装配对象,配置对象,并且管 理这些对象的整个生命周期。

什么是Spring inner beans?

其他介绍

为什么说Spring是一个容器?

用来形容它用来存储单例的bean对象这个特性。

Spring Bean的生命周期?

① Spring IoC容器找到关于Bean的定义并实例化该Bean。
② Spring IoC容器对Bean进行依赖注入。
③ 如果Bean实现了BeanNameAware接口,则将该Bean的id传给setBeanName方法。
④ 如果Bean实现了BeanFactoryAware接口,则将BeanFactory对象传给setBeanFactory方法。
⑤ 如果Bean实现了BeanPostProcessor接口,则调用其postProcessBeforeInitialization方法。
⑥ 如果Bean实现了InitializingBean接口,则调用其afterPropertySet方法。
⑦ 如果有和Bean关联的BeanPostProcessors对象,则这些对象的postProcessAfterInitialization方法被调用。
⑧ 当销毁Bean实例时,如果Bean实现了DisposableBean接口,则调用其destroy方法。

image-20200806223614200

哪些是重要的bean生命周期方法?你能重载它们吗?

有两个重要的bean生命周期方法,第一个是setup,它是在容器加载bean的时候被调用。第 二个方法是teardown它是在容器卸载类的时候被调用。 Thebean标签有两个重要的属性(init-method和destroy-method)。用它们你可以自己定制 初始化和注销方法。它们也有相应的注解(@PostConstruct和@PreDestroy)。

可以在Spring中注入一个null和一个空字符串吗?

可以

Spring使用

构建流程

首先编写pojo类,工厂

//定义一个宠物接口类
public interface Pet {
	public void testPet();
}
//定义两个宠物实现类

public class Dog implements Pet {
	private String name;
	public void setName(String name){
		this.name = name;
	}
	@Override
	public void testPet() {
		System.out.println(name+":狗喜欢吃骨头!");
	}
}


public class Cat implements Pet {
	private String name;
	public void setName(String name){
		this.name = name;
	}
	@Override
	public void testPet() {
		System.out.println(name+":猫喜欢吃鱼!");
	}
}
//定义一个静态工厂类

public class PetFactory {
	public static Pet getPet(String arg){
		if("dog".equals(arg)){
			return new Dog();
		}else{
			return new Cat();
		}
	}
}

一、创建applicationContext.xml文件

在这个文件中托管bean

<bean id = "dog" class = "cn.jimu98.factory.PetFactory" factory-method="getPet">
    <constructor-arg value="dog" />
    <property name="name" value = "旺财" />
</bean>
<bean id = "cat" class = "cn.jimu98.factory.PetFactory" factory-method="getPet">
    <constructor-arg value="cat" />
    <property name="name" value = "咪咪" />
</bean>

class属性就是指定的静态工厂类,factory-method指定工厂的静态方法。如果factory-method需要参数,则需要使用constructor-arg元素传入。

二、初始化容器

ApplicationContext ac = new ClassPathXmlApplicationContext(“ApplicationContext.xml”); //获取Spring 的上下文对象 也可以说拿到了容器

三、获取对象 getBean(“”)

//测试方法
public static void main(String[] args) throws Exception {
		ApplicationContext ac = new ClassPathXmlApplicationContext("appicationContext.xml");
		Pet p1 = ac.getBean("dog", Pet.class);
		p1.testPet();
		Pet p2 = ac.getBean("cat", Pet.class);
		p2.testPet();
	}
}

构造方法

无参构造

是指在实体类种通过无参构造器构造的bean

有参构造

ac.getBean(“dog”, Pet.class);

通过注解方式实现

在类上添加@Service注解

@Component:在Bean的实现类上直接标注,可以被Spring容器识别
@Repository:用于对DAO实现类进行标柱
@Service:用于对Service实现类进行标注
@Controller:用于对Controller实现类进行标注

—————————–分割线

其他

其实xml配置文件分类可多 细细道来

调用实例工厂方法创建Bean

<bean id = "petFactory" class = "cn.jimu98.factory.PetOneFactory" />
<bean id = "dog" factory-bean="petFactory" factory-method="getPet">
    <constructor-arg value="dog" />
    <property name="name" value = "旺财" />
</bean>

调用静态工厂方法只需要工厂类即可,而调用实例工厂方法则需要工厂实例。所以配置实例工厂方法与配置静态工厂方法基本相似,只有一点区别:配置静态工厂方法使用class指定静态工厂类,而配置实例工厂方法则使用factory-bean指定工厂实例。

抽象Bean与子Bean

在实际开发中,有可能会出现这样的情况:随着项目越来越大,Spring配置文件出现了多个bean,配置具有大致相同的配置信息,只有少量信息不同,为了解决上面问题,可以考虑把多个bean配置中相同的信息提取出来,集中成配置模板——这个配置模板并不是真正的Bean。因此Spring不应该创建该配置模板,于是需要为该bean配置增加abstract属性值为true表示这是个抽象Bean。

<bean id=”steelAxe” class=”cn.jimu98.impl.SteelAxe” />
<bean id=”personTemplete” abstract=”true”>
	<property name=”name” value=”zhangsan” />
	<property name=”axe” ref=”steelAxe” />
</bean>
<bean id=”chinese” class=”cn.jimu98.impl.Chinese” parent=”personTemplete”/>
<bean id=”american” class=”cn.jimu98.impl.American” parent=”personTemplete”/>

Java中Bean的继承与Java中的继承有如下区别:

Spring中的子Bean和父Bean可以是不同类型,但Java中的继承则可保证子类是一种特殊的父类。
Spring中Bean的继承是实例之间的关系,因此主要表现为参数值的延续;而Java中的继承是类之间的关系,主要表现为方法、属性的延续。
Spring中的子Bean不可作为父Bean使用,不具备多态性;Java中的子类实例完全可以当成父类实例使用。

Bean类的配置项

① class

该配置项是强制项,用于指定创建Bean实例的Bean类的路径。

② name

该配置项是强制项,用于指定Bean唯一的标识符,在基于 XML 的配置项中,可以使用 id和或 name 属性来指定 Bean唯一 标识符。

③ scope

该配置项是可选项,用于设定创建Bean对象的作用域。

④ constructor-arg

该配置项是可选项,用于指定通过构造函数注入依赖数据到Bean。

⑤ properties

该配置项是可选项,用于指定通过set方法注入依赖数据到Bean。

⑥ autowiring mode

该配置项是可选项,用于指定通过自动依赖方法注入依赖数据到Bean。

⑦ lazy-initialization mode

该配置项是可选项,用于指定IOC容器延迟创建Bean,在用户请求时创建Bean,而不要在启动时就创建Bean。

⑧ initialization

该配置项是可选项,用于指定IOC容器完成Bean必要的创建后,调用Bean类提供的回调方法对Bean实例进一步处理。

⑨ destruction

该配置项是可选项,用于指定IOC容器在销毁Bean时,调用Bean类提供的回调方法。

自动装配autowire

元素提供了一个default-autowire属性可以全局自动匹配,默认为no。元素提供了一个指定自动装配类型的autowire属性,可以覆盖元素的default-autowire属性,该属性有如下选项:

自动装配类型 说明
no 显式指定不使用自动装配。
byName 如果存在一个和当前属性名字一致的 Bean,则使用该 Bean 进行注入。如果名称匹配但是类型不匹配,则抛出异常。如果没有匹配的类型,则什么也不做。
byType 如果存在一个和当前属性类型一致的 Bean ( 相同类型或者子类型 ),则使用该 Bean 进行注入。byType 能够识别工厂方法,即能够识别 factory-method 的返回类型。如果存在多个类型一致的 Bean,则抛出异常。如果没有匹配的类型,则什么也不做。
constructor 与 byType 类似,只不过它是针对构造函数注入而言的。如果当前没有与构造函数的参数类型匹配的 Bean,则抛出异常。使用该种装配模式时,优先匹配参数最多的构造函数。
default 根据 Bean 的自省机制决定采用 byType 还是 constructor 进行自动装配。如果 Bean 提供了默认的构造函数,则采用 byType;否则采用 constructor 进行自动装配。

Bean的作用域

类型 说明
singleton 默认值,当IoC容器一创建就会创建bean的实例,Bean以单实例的方式存在
prototype 每次从容器中调用Bean时,都返回一个新的实例
request 每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境
session 同一个HTTP session共享一个Bean,不同的HTTP session使用不同的Bean,该作用域仅适用于WebApplicationContext环境
globalSession 该属性仅用于HTTP Session,同session作用域不同的是,所有的Session共享一个Bean实例。

扫描注解定义对Bean

Spring提供了一个context命名空间,用于扫描以注解定义Bean的类。

<!--生命context命名空间-->
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-4.0.xsd 
       http://www.springframework.org/schema/context 
       http://www.springframework.org/schema/context/spring-context-4.0.xsd">

    <context:component-scan base-package="cn.jimu98.spring"/>
</beans>
base-package属性
  • 指定一个需要扫描的基类包,Spring容器会扫描这个包下的所有类,并提取标注了相关注解的Bean。
resource-pattern属性
  • 如果不希望扫描base-package下的所有类,可以使用该属性提供过滤
  • 该属性默认是**/*.class,即基包下的所有类
context:exclude-filtercontext:include-filter
类别 示例 说明
annotation com.ankeetc.XxxAnnotation 所有标注了XxxAnnotation的类。该类型采用目标类是否标志了某个注解进行过滤。
assignable com.ankeetc.XxService 所有继承或扩展XXXService的类。该类型采用目标类是否继承或者扩展了某个特定类进行过滤
aspectj com.ankeetc..*Service+ 所有类名以Service结束的类及继承或者扩展他们的类。该类型采用AspectJ表达式进行过滤
regex com.ankeetc.auto..* 所有com.ankeetc.auto类包下的类。该类型采用正则表达式根据目标类的类名进行过滤
custom com.ankeetc.XxxTypeFilter 采用XxxTypeFilter代码方式实现过滤规则,该类必须实现org.springframework.core.type.TypeFilter接口
use-default-filters属性
  • use-default-filters属性默认值为true,表示会对标注@Component、@Controller、@Service、@Reposity的Bean进行扫描。
  • 如果想仅扫描一部分的注解,需要将该属性设置为false。
<!-- 仅扫描标注了@Controller注解的类-->
<context:component-scan base-package="com.ankeetc.spring" use-default-filters="false">
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

自动装配

方式一:通过xml文件实现自动装配
<bean id="people" class="cn.jimu98.pojo.Peopel" autowire="byName">
        <property name="name" value="张三"/>
</bean>

使用autowire关键字声明bean的自动装配方式。其可选值为byName、byType、constructor,default,no;这里讲前边两个。

1.byName

设置autowire属性为byName,那么Spring会根据class属性找到实体类,然后查询实体类中所有setter方法的名字,根据setter方法后面的名字(例如SetDog,则setter方法后面的名字为dog)再到配置文件中寻找一个与该名字相同id的Bean,注入进来。如图:

image-20200806213043989

2.byType

设置autowire属性为byType,那么Spring会自动寻找一个与该属性类型相同的Bean,注入进来。

image-20200806213100822

注意:使用byType这种方式,必须保证配置文件中所有bean的class属性的值是唯一的,否则就会报错

例如:下边这种方式是错误的,因为两个bean中的class属性的值重复了,会报错

image-20200806213136630

方式二:通过注解实现自动装配

注解是通过反射来实现的。

1.使用注解前的准备:

要使用注解,xml文件要使用如下的文件头:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>

</beans>

注意:
<context:annotation-config/> 必须要写在xml中,这是用来开启注解的支持,如果不加上注解就无效。

2.1 Autowired注解【常用】
首先xml配置文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>

    <bean id="cat" class="com.kuang.pojo.Cat"/>
    <bean id="dog" class="com.kuang.pojo.Dog"/>
    <bean id="people" class="com.kuang.pojo.Peopel">
        <property name="name" value="张三"/>
    </bean>
</beans>

然后在实体类的对应属性上添加@Autowired注解(也可以把注解放到对应属性的setter上),people类中依赖Dog类和Cat类。所以在people类中的dog和cat属性上要加上@Autowired,实现自动装配。

例如:

public class Peopel {
    @Autowired
    private Cat cat;
    @Autowired
    private Dog dog;
    private String name;

    public Cat getCat() {
        return cat;
    }
    public void setCat(Cat cat) {
        this.cat = cat;
    }
    public Dog getDog() {
        return dog;
    }
    public void setDog(Dog dog) {
        this.dog = dog;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "Peopel{" +
                "cat=" + cat +
                ", dog=" + dog +
                ", name='" + name + '\'' +
                '}';
    }
}

重点:

(1)注解方法装配属性的过程:spring会默认优先根据(被注解修饰的)属性类型去容器中找对应的组件(bean),找到就赋值;若找到多个相同类型的组件,再将属性的名称作为组件(bean)的id去容器中查找。

(2)@Qualifier注解可以和使用Autowired搭配使用:@Qualifier指定需要装配的组件的id,而不是使用属性名。例如下边例子,spring就会优先在容器中查找id为“abcd”的组件。

public class Peopel {
    @Autowired
    @Qualifier(value = "cat")
    private Cat cat;
}

什么情况会使用到@Qualifier注解:当ioc容器根据属性类型去容器中找找到多个相同类型的组件,再将属性的名称作为组件(bean)的id去容器中查找找不到时就是用这两个注解搭配,指定需要装配的bean的id。

(3)在默认情况下使用 @Autowired 注释进行自动注入时,Spring 容器中匹配的候选 Bean 数目必须有且仅有一个。当找不到一个匹配的 Bean 时,Spring 容器将抛出 BeanCreationException 异常,并指出必须至少拥有一个匹配的 Bean。当不能确定 Spring 容器中一定拥有某个类的 Bean 时,可以在需要自动注入该类 Bean 的地方可以使用@Autowired(required= false)。这等于告诉 Spring:在找不到匹配 Bean 时也不报错。

2.2. Resource注解【不常用】

@Resource:可以和@Autowired一样实现自动装配功能,但是跟@Autowired不一样的是,它默认是按照组件名称进行装配的,按照组件名称找不到在根据属性类型去查找,再找不到就报错;他们另一个不同的地方就是@Autowired是Spring定义的; @Resource是java规范。

什么是Spring inner beans?

在Spring框架中,无论何时bean被使用时,当仅被调用了一个属性。一个明智的做法是将这 个bean声明为内部bean。内部bean可以用setter注入“属性”和构造方法注入“构造参数”的方式来实现。 比如,在我们的应用程序中,一个Customer类引用了一个Person类,我们的要做的是创建 一个Person的实例,然后在Customer内部使用。

public class Customer{
 private Person person;
 //Setters and Getters
}

public class Person{
 private String name;
 private String address;
 private int age;
 //Setters and Getters
}
<bean id="CustomerBean" class="com.somnus.common.Customer">
 <property name="person">
 <!-- This is inner bean -->
 <bean class="com.howtodoinjava.common.Person">
 <property name="name" value="lokesh" />
 <property name="address" value="India" />
 <property name="age" value="34" />
 </bean>
 </property>
</bean>

pring框架中的单例bean不是线程安全的。

请举例说明@Qualiier注解?

@Qualiier注解意味着可以在被标注bean的字段上可以自动装配。Qualiier注解可以用来取 消Spring不能取消的bean应用。 下面的示例将会在Customer的person属性中自动装配 person的值。

<bean id="customer" class="cn.jimu98.common.Customer" />
<bean id="personA" class="cn.jimu98.common.Person" >
 <property name="name" value="lokesh" />
</bean>

<bean id="personB" class="cn.jimu98.common.Person" >
 <property name="name" value="alex" />
</bean>
public class Customer{
 @Autowired
 private Person person;
}

//这样就会报错,因为不知道该使用哪个bean

public class Customer{
 @Autowired
 @Qualifier("personA")
 private Person person;
}

//使用@Qualiier注解就ok了

IOC

从注入方法上看,IoC可以分为:构造函数注入、属性注入、接口注入

构造函数注入
class KFCCombo {
    private Burger burger;
    private Drink drink;

    // 在此注入对应的内容
    public KFCCombo(Burger burger, Drink drink) {
        this.burger = burger;
        this.drink = drink;
    }
}
属性注入
class KFCCombo {
    private Burger burger;
    private Drink drink;

    // 在此注入对应的内容
    public void setBurger(Burger burger) {
        this.burger = burger;
    }

    // 在此注入对应的内容
    public void setDrink(Drink drink) {
        this.drink = drink;
    }
}
接口注入
interface InjectFood {
    void injectBurger(Burger burger);
    void injectDrink(Drink drink);
}

class KFCCombo implements InjectFood {
    private Burger burger;
    private Drink drink;
    
    // 在此注入对应的内容
    public void injectBurger(Burger burger) {
        this.burger = burger; 
    }
    // 在此注入对应的内容
    public void injectDrink(Drink drink) {
        this.drink = drink;
    }
}

接口注入和属性注入并无本质的区别,而且还增加了一个额外的接口导致代码增加,因此不推荐该方式。

资源访问

classpath:与classpath*:

假设有多个Jar包或者文件系统类路径下拥有一个相同包名(如com.ankeetc):

  • classpath:只会在第一个加载的com.ankeetc包的类路径下查找
  • classpath*:会扫描到所有的这些JAR包及类路径下出现的com.ankeetc类路径。

这对于分模块打包的应用非常有用,假设一个应用分为2个模块,每一个模块对应一个配置文件,分别为module1.yaml 、module2.yaml,都放在了com.ankeetc的目录下,每个模块单独打成JAR包。可以使用 classpath*:cn/jimu98/module*.xml加载所有模块的配置文件。

Spring配置

Spring有几种配置方式?

将Spring配置到应用开发中有以下三种方式:

1.基于XML的配置

2.基于注解的配置

3.基于Java的配置

如何用基于XML配置的方式配置Spring?

如何用基于Java配置的方式配置Spring?

定义一个配置类

怎样用注解的方式配置Spring?

import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringIdolConfig {
	// Bean declaration methods go here
}

声明一个简单的Bean

@Bean
public Performer duke() {
	return new Juggler();
}

使用Spring的基于java的配置进行注入。

@Bean
public Performer duke15() {
	return new Juggler(15);
}
@Bean
public Performer kenny() {
    Instrumentalist kenny = new Instrumentalist();
    kenny.setSong("Jingle Bells");
    return kenny;
}

Spring面试题

Spring支持的常用数据库事务传播属性和事务隔离级别?

事务传播行为用来描述由某一个事务传播行为修饰的方法被嵌套进另一个方法的时事务如何传播。

Spring中的隔离级别

常量 解释
ISOLATION_DEFAULT 这是个 PlatfromTransactionManager 默认的隔离级别,使用数据库默认的事务隔离级别。另外四个与 JDBC 的隔离级别相对应。
ISOLATION_READ_UNCOMMITTED 这是事务最低的隔离级别,它充许另外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读。
ISOLATION_READ_COMMITTED 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。
ISOLATION_REPEATABLE_READ 这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。
ISOLATION_SERIALIZABLE 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。

Spring 事务的传播属性

所谓spring事务的传播属性,就是定义在存在多个事务同时存在的时候,spring应该如何处理这些事务的行为。这些属性在TransactionDefinition中定义,具体常量的解释见下表:

常量名称 常量解释
PROPAGATION_REQUIRED 支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择,也是 Spring 默认的事务的传播。
PROPAGATION_REQUIRES_NEW 新建事务,如果当前存在事务,把当前事务挂起。新建的事务将和被挂起的事务没有任何关系,是两个独立的事务,外层事务失败回滚之后,不能回滚内层事务执行的结果,内层事务失败抛出异常,外层事务捕获,也可以不处理回滚操作
PROPAGATION_SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY 支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER 以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED 如果一个活动的事务存在,则运行在一个嵌套的事务中。如果没有活动事务,则按REQUIRED属性执行。它使用了一个单独的事务,这个事务拥有多个可以回滚的保存点。内部事务的回滚不会对外部事务造成影响。它只对DataSourceTransactionManager事务管理器起效。

Spring支持的事务管理类型

Spring支持两种类型的事务管理:

编程式事务管理:这意味你通过编程的方式管理事务,给你带来极大的灵活性,但是难维 护。

声明式事务管理:这意味着你可以将业务代码和事务管理分离,你只需用注解和XML配置 来管理事务。

Spring事务隔离级别与Mysql InnoDB事务隔离级别冲突了怎么办

  • Spring会在事务开始时,根据你程序中设置的隔离级别,调整数据库隔离级别与你的设置一致。
  • 当使用Serializable级别时,Mysql在执行SQL时会自动修改为select .... lock in share mode, 即使用共享锁。此时允许同时读,但只允许一个事务写,且锁的是行而不是整张表

这意味着:

  • 如果数据库不支持某种隔离级别,那么Spring设置了也无效。
  • 当使用Serializable级别时,如果两个事务读写的不是同一行,那么它们是互不影响的。如果操作同一行记录,那么允许同时读,但如果出现一个对此行的写操作,则在写事务没有提交之前,所有的读事务都会被block。

Spring 框架中用到了哪些设计模式?

代理模式—在 AOP 和 remoting 中被用的比较多。
单例模式:在 spring 配置文件中定义的 bean 默认为单例模式。
模板方法:用来解决代码重复的问题。比如. RestTemplate, JmsTemplate, JpaTemplate。
前端控制器:Spring 提供了 DispatcherServlet 来对请求进行分发。
视图帮助(View Helper ):Spring 提供了一系列的 JSP 标签,高效宏来辅助将分散的代码 整合在视图里。
依赖注入:贯穿于 BeanFactory / ApplicationContext 接口的核心理念。
工厂模式:BeanFactory 用来创建对象的实例。