Spring知识小结

目录

1.使用依赖注入的好处

2.控制反转

3.常用注解

3.1 @Configuration

3.2 @Component

3.3 @Reponstory

3.4 @Service

3.5 @Controller

3.6 @Bean

3.7 @Autowired

3.8 @Qualifier

3.9 @Value

3.10 @ComponentScan

3.11 @PropertySource

3.12 @Import

4.依赖注入发生时间

5. BeanFactory和FactoryBean的区别

5.1 BeanFactory       

5.2 FactoryBean

6.Bean的生命周期

7.为什么要使用三级缓存来解决循环依赖

7.1 什么是循环依赖

7.2 在 Spring 中使用循环依赖

7.2.1 实体类

7.2.2 配置

7.2.3 配置类

7.2.4 测试类

7.3 分析解决循环依赖的问题

8.AOP

8.1 横切关注点

8.2 切面

8.3 连接点

8.4 切入点

9.事务管理

9.1 事务的特点

9.2 事务隔离级别

9.3 事务传播行为


1.使用依赖注入的好处

  • 解耦。我们之前使用new来创建对象,是硬编码。(硬编码比较死板,不利于修改和扩展)当使用配置方式后,就不用我们手动new对象,创建对象的时机就交给Spring框架来完成。
  • 灵活。(修改和扩展是可以直接在配置文件中进行操作)

2.控制反转

        控制反转(Inversion of Control,Ioc),它是spring框架中的核心之一,指的是对象成员变量的赋值控制权由原来我们自己创建,变为交给Spring来创建。

3.常用注解

3.1 @Configuration

        它是标注在类上的,被它标注的类就是一个配置类,它的使用就相当于applicationContext.xml文件的作用。

3.2 @Component

        这个注解是让Spring容器在加载时自动会添加到容器里面的注解。它也是标注在类上的。它在Spring容器中就相当于一个Bean标签。

public @interface Component {

	/**
	 * 该值可能指示对逻辑组件名称的建议,
	 * 在自动检测组件的情况下被转换为SpringBean.
	 * 返回建议的组件名称(如果有的话)(否则返回空字符串)
	 */
	String value() default "";

}

3.3 @Reponstory

        这个注解的作用与@Component注解的作用和功能一样。但从语义层面来说,这个注解用于数据访问层,而@Component常用于层次不太明确或没有层次的地方。

public @interface Repository {

	/**
	 * 该值可能指示对逻辑组件名称的建议,
	 * 在自动检测组件的情况下被转换为SpringBean.
	 * 返回建议的组件名称(如果有的话)(否则返回空字符串)
	 */

    // Component的别名 
	@AliasFor(annotation = Component.class)
	String value() default "";

}

3.4 @Service

        这个注解的作用也与@Component注解的作用和功能一样。但从语义层面来说,这个注解用于业务逻辑层。

public @interface Service {

	/**
	 * 该值可能指示对逻辑组件名称的建议,
	 * 在自动检测组件的情况下被转换为SpringBean.
	 * 返回建议的组件名称(如果有的话)(否则返回空字符串)
	 */
    
    // Component的别名 
	@AliasFor(annotation = Component.class)
	String value() default "";

}

3.5 @Controller

        这个注解的作用与@Component注解的作用和功能一样。但从语义层面来说,这个注解用于控制访问层。

public @interface Controller {

	/**
	 * 该值可能指示对逻辑组件名称的建议,
	 * 在自动检测组件的情况下被转换为SpringBean.
	 * 返回建议的组件名称(如果有的话)(否则返回空字符串)
	 */
    
    // Component的别名 
	@AliasFor(annotation = Component.class)
	String value() default "";

}

3.6 @Bean

        它是标注在一个方法上的,这个注解可以给它一个name/value属性,用于给这个Bean对象取一个唯一的名称,便于调用。如果没有给定name/value属性,那么被这个注解所标注的方法所对应的名称就是方法名称。

3.7 @Autowired

        这个注解可以添加到成员属性、方法参数、构造方法上。它的作用是把标注的对象进行自动注入(装配)。被它注解的对象默认是按照类型来自动装配。如果希望按照名称来进行自动装配,那么要结合@Qualifier注解一起使用。

3.8 @Qualifier

        它的作用是配合@Autowired注解来按名称进行装配,它不能独立使用。如果希望能够独立使用,则只能放到参数列表中。 

3.9 @Value

        这个注解的作用是对基本数据类型和字符串类型进行注入值。

3.10 @ComponentScan

        这个注解是用于类上的,它的作用是对指定名路径进行扫描。

3.11 @PropertySource

        这个注解的作用是加载.properties文件中的配置。

3.12 @Import

        这个注解是用于标注在类上的,作用是导入其它的配置类,它是可以一次导入多个配置类。

@Import{(xxx.class,xxxx.class)}

4.依赖注入发生时间

        当Spring IoC容器完成了Bean定义资源的定位、载入和解析注册后,IoC容器就可以管理Bean定义的相关数据。但是,此时IoC容器还没有对所管理的Bean进行依赖注入,依赖注入是在以下两种情况下产生的:

  1.  当用户第一次调用getBean()方法时,IoC容器触发依赖注入。
  2.  当用户在配置文件中将<Bean>元素配置了lazy-init=false属性时,IoC容器才回进行预实例化,触发依赖注入。

5. BeanFactory和FactoryBean的区别

区别:BeanFactory是管理Bean的工厂,而Factory是创建对象的工厂Bean

5.1 BeanFactory       

        BeanFactory是IoC容器的核心接口,可以进行实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。它定义了IoC的容器的最基本形式,并不是IoC的具体实现。但是Spring容器给出了很多种实现,如 DefaultListableBeanFactory、XmlBeanFactory、ApplicationContext等,都是附加了某种功能的实现。

public interface BeanFactory {

	
	String FACTORY_BEAN_PREFIX = "&";

    // 返回给定名称注册的bean实例。根据bean的配置情况,如果是singleton模式将返回一个共享实例,否则将返回一个新建的实例,如果没有找到指定bean,该方法可能会抛出异常	
	Object getBean(String name) throws BeansException;

    // 返回以给定名称注册的bean实例,并转换为给定class类型	
	<T> T getBean(String name, Class<T> requiredType) throws BeansException;

	// 判断工厂中是否包含给定名称的bean定义,若有则返回true
	boolean containsBean(String name);

	// 判断给定名称的bean定义是否为单例模式
	boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
    
	// 返回给定名称的bean的Class,如果没有找到指定的bean实例,则抛出NoSuchBeanDefinitionException异常
	@Nullable
	Class<?> getType(String name) throws NoSuchBeanDefinitionException;

	// 返回给定bean名称的所有别名
	String[] getAliases(String name);

}

5.2 FactoryBean

        一般情况下,Spring通过反射机制利用<bean>的class属性指定实现类实例化Bean,在某些情况下,实例化Bean过程比较复杂,如果按照传统的方式,则需要在<bean>中提供大量的配置信息。配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。Spring为此提供了一个org.springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化Bean的逻辑。

        从Spring3.0开始,FactoryBean开始支持泛型,即接口声明改为FactoryBean<T>的形式以Bean结尾,表示它是一个Bean,不同于普通Bean的是:它是实现了FactoryBean<T>接口的Bean,根据该Bean的ID从BeanFactory中获取的实际上是FactoryBean的getObject()返回的对象,而不是FactoryBean本身,如果要获取FactoryBean对象,请在id前面加一个&符号来获取。

public interface FactoryBean<T> {

	
	String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";


	// 获取当前对象
	@Nullable
	T getObject() throws Exception;

	// 获取当前对象的类型
	@Nullable
	Class<?> getObjectType();

	// 默认值为true 是单例对象  false 不是单例对象
	default boolean isSingleton() {
		return true;
	}

}

6.Bean的生命周期

在Spring中Bean的生命周期可以分为4类:

  • Bean 自身方法
  • Bean 生命周期接口方法
  • 容器级别生命周期接口方法
  • 工厂后处理器接口方法
Spring Bean 生命周期相关接口及方法
Bean 自身方法

Bean本身业务的方法

配置文件中 init-method 和 destroy-method 指定的方法

Bean 生命周期接口方法

InitializingBean 接口

DisposableBean 接口

BeanNameAware 接口

ApplicationContextAware 接口

BeanFactoryAware 接口

其它

容器级别生命周期接口方法

一般称为后处理器

InstantitationAwareBeanPostProcessor 接口实现

BeanPostProcesso r接口实现

工厂后处理器接口方法

也可以归为容器级别

AspectJWeavingEnabler

ConfigurationClassPostProcessor

CustomAutowireConfigure r等

一个 Bean 的生命周期需要经历以下时序:

  • init-method:指定某个方法在 Bean 实例化完成,依赖关系设置结束后执行
  • detroy-method:指定某个方法在 Bean 销毁之前被执行
  • InitializingBean 接口:在 Bean 实例化完成,依赖关系设置结束后执行,在 init-method 之前 执行
  • DisposableBean 接口:在指定 Bean Bean 销毁之前被执行,它是在 detroy-method 之前执行
  • ApplicationContextAware 接口:在实例化 Bean 时,为 Bean 注入 ApplicationContext7 

7.为什么要使用三级缓存来解决循环依赖

7.1 什么是循环依赖

        循环依赖就是 A 的创建依赖于 B 的创建,B 的创建又依赖于 C 的创建,而 C 的创建又依赖于 A 的创建。

 如上图的所示就形成了循环依赖。

7.2 在 Spring 中使用循环依赖

7.2.1 实体类

@Component
public class AService {
    @Autowired
    private BService bService;

    public void show() {
        System.out.println(bService);
    }
}



@Component
public class BService {
    @Autowired
    private AService aService;

}

7.2.2 配置

 <bean id="aService" class="com.funny.service.AService">
        <property name="BService" ref="bService"/>
    </bean>

    <bean id="bService" class="com.funny.service.BService">
        <property name="AService" ref="aService"/>
    </bean>

7.2.3 配置类

@Configuration
@ComponentScan("com.funny")
public class AppConfig {
}

7.2.4 测试类

public class test {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(AppConfig.class);
        AService aService = (AService) context.getBean("AService");
        aService.show();
    }

通过测试发现,在Spring中已经帮我们解决一些循环依赖的问题。 

7.3 分析解决循环依赖的问题

在 Spring 中,创建一个对象需要经过以下步骤:

1)利用构造器创建一个普通对象(也叫原始对象)

2)给对象的属性赋值,也就填充对象的属性值

3)填充其他属性

4)初始化前、初始化完成,以及其它操作 

5)初始化后

6)把创建并初始化的对象放到单例池中(singletoObjects)里面。

在 Spring 中,通过以下三个 Map 对象来解决循环依赖问题:

1、一级缓存:singletonObjects,在这级缓存中已经经历完整的生命周期的 Bean 对象

2、二级缓存:earlySingletonObjects,比一级缓存多了一个 early,表示缓存的是早期的 Bean 对 象,也就是 Bean 的生命周期还没有走完就把这个 Bean 放到了二级缓存中。

3、三级缓存:singletonFactories,缓存的是 ObjectFactory ,表示对象工厂,用来创建某个对 象。 实际上,大多数据开发部下使用一级缓存就可以解决循环依赖问题,如果在循环依赖中存在一些 循环的属性需要注入,比如 AOP 相关的数据需要注入,这时就需要使用 三级缓存来解决循环依赖问题。

 从上图中可以发生,Spring 在处理循环依赖问题时,使用二级缓存就已经解决,但它不能解决复 杂的循环依赖问题。要想解决复杂的循环依赖问题,就需要用到三级缓存。

8.AOP

AOP(Aspect Oriented Programming)面向切面编程,它是面向对象编程的一种补充。

 在 Spring 中,AOP 的实现有两种方式:

  • 使用 JDK 动态代理,要求被增强(代理)对象必须实现接口
  • 使用 CGLib 动态代理

在 Spring 中两种方式都有,如果被代理对象实现了接口就使用 JDK 动态代理,否则就使用 CGLib 动态代理。默认使用的是 JDK 动态代理。我们可以设置使用何种代理方式。

8.1 横切关注点

        简单的说,横切关注点就是可以对某些方法进行拦截,拦截后对原方法进行增强的处理。

8.2 切面

        切面就是对横切关注点的抽象,这个关注点可能会横切多个对象。简单的说就是用于增强的类。

8.3 连接点

        连接点是在程序执行过程中某个特定的点,如某个方法调用时或者处理异常的时。

8.4 切入点

        在切面上拦截到某个特定的连接点之后执行的动作。

9.事务管理

数据库的事务是指将一系列的数据库操作当作一个逻辑单元,这个单元中的数据操作要么完全成 功,要么完全失败。

9.1 事务的特点

一个事务处理逻辑单元要成为事务,必须满足ACID属性:

  • 原子性(Atomicity):一个事务内的操作不可再分,要么全部成功,要么全部失败。
  • 一致性(Conisitency):事务执行后,数据库的状态与其他业务逻辑保持一致。
  • 隔离性(Isolation):每个事务运行都是相互独立的,互不干绕。
  • 持久性(Druability):事务一旦提交,就会永久保存下来。

9.2 事务隔离级别

事务隔离级别有4个:

  • READ_UNCOMMITED:读未提交,会产生“脏读”数据,必须要避免的。
  • READ_COMMITED:读已提交事务,会产生“幻读”数据。
  • REPEATABLE_READ:可重复读,会产生“幻读”数据。
  • SERIALIZABLE:它是一个串行读。

事务隔离级别是从上往下的安全性增加,但是性能降低。

9.3 事务传播行为

事务传播行为有7个:

事务传播行为类型说 明
PROPAGATION_REQUIRED

如果当前没有事务,就新建一个事务。

如果已经存在一个事务中,加入到这就个事务中

PROPAGATION_SUPPORTS支持当前事务。如果当前没有事务,就以非事务方式执 行
PROPAGATION_MANDATORY使用当前的事务。如果当前没有事务,就抛出异常
PROPAGATION_REQUIRES_NEW新建事务。如果当前存在事务,把当前事务挂起
PROPAGATION_NOT_SUPPORTED以非事务方式执行操作。如果当前存在事务,就把当前 务挂起
PROPAGATION_NEVER以非事务方式执行。如果当前存在事务,则抛出异常
PROPAGATION_NESTED

如果当前存在事务,则在嵌套事务内执行。

如果当前没有事务,则执行与 PROPAGATION_REQUIRED 类似的操作。

与 PROPAGATION_REQUIRES_NEW 的差别是 PROPAGATION_REQUIRES_NEW 另起一个事务,将会与 其父事务相互独立。

PROPAGATION_NESTED 事务和其父事务是相依的,其要 等父事务一起提交。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值