Spring归档

本文起草于2020年6月14日,最后更新于2020年6月17日,随时间推移,文章内容可能会被更新。

spring-context:5.1.6.RELEASE

概述

Spring框架是 Java 平台的一个开源的全栈应用程序框架和控制反转容器实现,一般被直接称为Spring。该框架的一些核心功能理论上可用于任何Java 应用,但 Spring 还为基于Java企业版平台构建的Web 应用提供了大量的拓展支持。

IOC 控制反转

创建对象的权限从开发人员手中反转到Spring框架中。

Spring框架会根据配置文件,利用反射技术提前创建好对象,并存入容器中。

//读取配置文件,初始化Spring容器
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//从容器中get bean
Object dataSource = context.getBean("dataSource");
return dataSource;
<!--数据源示例-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"/>

IOC容器启动过程中会执行哪些操作?

1.读取xml文件,得到bean id 和 class(全限定类名)

2.根据读取到的class属性寻找真正的Class字节码(Class.forName())

3.利用反射技术,创建对象

4.将创建好的对象存储到自身的map结构中,以bean id为key 创建好的对象为value

5.等待调用

API

接口:
BeanFactory:Spring IOC容器顶级接口,它定义了Spring IOC最基础的功能,一般面向Spring自身使用。
ApplicationContext:BeanFactory的衍生接口,它拓展了BeanFactory的功能,一般面向开发人员使用。
BeanFactory在第一次使用bean(调用getBean方法)时才对该bean加载实例化,而ApplicationContext在容器初始化时就一次性加载所有bean。他们创建出来的对象都是单例模式。
实现类:
这三个实现类的作用都是读取配置文件,初始化Spring容器。
ClassPathXmlApplicationContext:读取类路径下的xml作为配置文件
FileSystemXmlApplicationContext:读取本地目录下的xml作为配置文件
AnnotationConfigApplicationContext:读取Java类作为配置文件
getBean方法
getBean(String var1):使用bean id作为条件,获取对象
getBean(Class<T> var1):使用bean的Class作为参数,获取对象
getBean(String var1, Class<T> var2):使用bean id和class作为参数,获取对象

作用域和生命周期

<!--单例模式 scope=singleton(默认)-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" scope="singleton"/>
<!--多例模式 scope=prototype-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" scope="prototype"/>
@Scope:可以指定创建对象的模式(单例、多例)

单例对象的生命周期:Spring容器初始化时创建对象,Spring容器关闭时销毁对象。

多例对象的生命周期:每一次调用getBean()方法时创建对象,由Java垃圾回收机制回收对象。

依赖注入(XML)

依赖注入(又称DI),是指给对象中的属性赋值的过程。

依赖注入有两种方式,分别是使用构造函数注入和调用set方法注入。

使用构造方法注入:必须传递构造函数所需的全部参数,但可以保证完整性。

<!--name:构造方法的形参 value:依赖注入的值(简单类型) ref:依赖注入的值(IOC容器中bean的id,引用类型)-->
<bean id="" class="">
    <constructor-arg name="" value="" 或 ref=""/>
</bean>

使用set方法注入:

<!--name:set方法的方法名,set后面的一部分,首字母小写-->
<bean id="" class="">
    <property name="" value="" 或 ref=""/>
</bean>
<!--另一种形式,不常用-->
<bean id="" class=""
p:name="" p:price="">
</bean>

单列集合的依赖注入(list set array)

<!--list set array标签可以互换-->
<bean id="" class="">
    <property name="list集合名字">
        <list>
            <value>AA</value>
            <value>BB</value>
        </list>
    </property>
    
    <property name="set集合名字">
        <set>
            <value>AA</value>
            <value>BB</value>
        </set>
    </property>

    <property name="array集合名字">
        <array>
            <value>AA</value>
            <value>BB</value>
        </array>
    </property>
</bean>

双列集合的依赖注入(map properties)

<!--map props标签可以互换-->
<bean id="" class="">
    <property name="map集合名字">
        <map>
            <entry key="AA" value="BB"></entry>
        </map>
    </property>

    <property name="properties集合名字">
        <props>
            <prop key="AA">BB</prop>
        </props>
    </property>
</bean>

单列集合的标签可以互换,双列集合的标签可以互换。

依赖注入(注解版)

对象的创建

<!--包扫描-->
<!--指定一个包名,当前包及其子包类上的注解才会生效-->
<context:component-scan base-package=""/>

@ComponentScan(basePackages = "org.shiro")
@Controller  @Service  @Repository  @Component 
标注在类上,表示Spring要创建该类的对象,并将创建好的对象放入IOC容器中。

String value() default "";
支持一个属性value,可以指定bean的id。如果不指定,默认id为类名首字母小写(小驼峰)。
@Scope:可以指定创建对象的模式(单例默认、多例singleton)
@Autowired:用于进行依赖注入,可以标注在属性上,也可以标注在方法上(例如标注在set方法上)。
@Qualifier:用于按照指定的bean id在容器中进行匹配。
标注在属性上:
Spring首先在容器中根据属性的类型在IOC容器中查找。如果没有找到,则注入失败。如果找到一个,则进行注入。
如果找到多个,则再次根据属性的名字在IOC容器中查找。如果找到一个,则进行注入,否则注入失败。
标注在方法上:
被@Autowired标注的方法会自动运行。
当方法需要参数时,Spring会进行依赖注入。依赖注入步骤同上。
//@Bean完全相当于@Autowired标注在方法上的作用
//@Bean还会将方法的返回对象放到IOC容器中,可以声明生成对象的id,默认值是当前方法名首字母小写。
@Bean("dataSource")
public DruidDataSource getDruidDataSource() {
    DruidDataSource dataSource = new DruidDataSource();
    dataSource.setDriverClassName(driver);
    dataSource.setUrl(url);
    dataSource.setUsername(username);
    dataSource.setPassword(password);
    return dataSource;
}

@Bean
public QueryRunner queryRunner(DataSource dataSource) {
    QueryRunner queryRunner = new QueryRunner(dataSource);
    return queryRunner;
}

其他注解

@Configuration:被此注解声明的类会被Spring认为是配置类。
Spring在启动时会自动扫描并加载所有的配置类,然后将配置类中的bean放入容器。

@PropertySource("文件名"):用于读取一个property作为配置文件。
使用时@Value("${key}")对变量进行赋值。

AOP 面向切面编程

当核心业务(如转账)和增强业务(如事务问题)同时出现时,我们可以在开发时对它们分别开发,运行时再组装到一起(使用动态代理)进行运行。

这是一种AOP思想,它的目的是在不修改源代码的基础上,对原有功能进行增强。

Spring AOP是对AOP思想的一种实现。这种思想的好处是:

1.逻辑清晰,开发核心业务时不用关注增强业务

2.代码复用性高,增强代码不用重复开发

既:开发时分别开发,组装时组装运行

Spring AOP

目标对象:被代理类产生的对象
连接点:目标对象中的所有方法
切入点:目标对象中要增强的方法
增强(通知):一个具体的增强功能(如事务、打日志)
织入:将增强功能和切入点柔和在一起的动作
代理对象:经过动态代理产生的对象
切面:切点+增强,可以理解为一个什么样的增强功能加入到切点的什么位置

开发时,一般要经过以下三个步骤:

1.开发目标方法

2.开发增强方法

3.配置切面(增强方法添加到目标方法的什么位置)

<!--创建目标对象和增强对象到IOC容器中-->
<bean id=目标对象 class=""></bean>
<bean id=增强对象 class=""></bean>

<!--AOP配置-->
<aop:config>
    <!--提取公共的切点表达式,方便引用-->
    <aop:pointcut id="" expression="切点表达式"></aop:pointcut>
    <!--配置切面 四大通知-->
	<aop:aspect id="切点标识" ref="增强对象">
    	<aop:before method="增强方法" pointcut="切点表达式"/>
        <aop:after-returning method="增强方法" pointcut-ref="切点表达式引用"/>
        <aop:after-throwing method="增强方法" pointcut="切点表达式"/>
        <aop:after method="增强方法" pointcut="切点表达式"/>
    </aop:aspect>
</aop:config>

切点表达式

示例:
execution (* com.example.dao.impl.TeacherDaoImpl.teach())

execution (* com.example.dao.impl.TeacherDaoImpl.*(..))//不限制参数个数

execution (* com.example.dao.impl.*.*(..))//切impl包下所有类的所有方法

*表示一个或多个

..表示0个或多个

四大通知

<aop:aspect id="切点标识" ref="增强对象">
    	<aop:before method="" pointcut=""/>
        <aop:after-returning method="" pointcut=""/>
        <aop:after-throwing method="" pointcut=""/>
        <aop:after method="" pointcut=""/>
</aop:aspect>

before:前置通知,在切点方法执行之前执行

after-returning:后置通知,在切点方法正常运行之后运行

after-throwing:异常通知,在切点方法抛出异常之后运行

after:最终通知,在切点方法运行最后运行

环绕通知

环绕通知是一种允许开发人员以编码形式实现的通知类型,可以使用它替换四大通知。

@Aspect//将增强类转为切面类
增强类......
    
    
@Around("切点表达式")
public void aroundMethod(ProceedingJoinPoint p){
    try {
        //todo 前置通知
            p.proceed();//表示切点方法运行
        //todo 后置通知
        } catch (Throwable e) {
        	//todo 异常通知
            e.printStackTrace();
        } finally {
        	//todo 最终通知
        }
}

使用注解版需要开启自动代理

@EnableAspectJAutoProxy
<apo:aspectj-autoproxy/>

或使用XML配置

<aop:aspect id="切点标识" ref="增强对象">
    	<aop:around method="环绕通知方法" pointctt=""/>
</aop:aspect>

Spring AOP 工作原理

开发阶段

开发目标对象,开发增强功能,配置切面。

运行阶段

Spring会时刻监测切点方法的运行,一旦发现程序运行到了切点,Spring会立即将增强方法放置到切点方法的相应位置,达到组装运行的效果。

Spring 事务管理

PlatformTransactionManager

事务管理器顶级根接口,实现事务管理功能。

实现类根据不同的Dao框架进行实现,其中可以对MyBatis和JDBC Templete进行事务管理的实现类是DataSourceTransactionManager

TransactionDefinition

作为事务管理器的参数传递,可以设置事务的隔离级别、传播行为、只读性、超时时长。

隔离级别:读未提交,读已提交,可重复读,串行化。

传播行为:当一个业务被另一个业务调用时,应该如何控制事务。

PROPAGATION_REQUIRED 默认 必须有事务,存在则加入,没有则开启
PROPAGATION_SUPPORTS 常用 支持有事务,如果存在事务则加入,如果没有则非事务运行
PROPAGATION_REQUIRED_NEW 总是开启一个新事务
PROPAGATION_NOT_SUPPORTS 总是不支持事务
PROPAGATION_MANDATORY
PROPAGATION_NEVER

只读性:只读事务只能用于查询方法。

超时时长:事务的超时时长,超时之后执行一系列操作如回滚,需要数据库底层支持。

TransactionStatus

代表事务的状态

使用Spring进行事务管理的步骤:

1.开发目标对象(如转账)

2.增强对象由Spring提供DataSourceTransactionManager,不需要我们开发,但需要传递一些参数(TransactionDefinition)。

3.配置切面

<!--配置事务管理器...-->
<bean id class/>

<!--给事务管理器传递参数,传了才算增强-->
<tx:advice id="txAdvice" transaction-manager="指定事务管理器,默认为transactionManaget">
	<tx:attributes>
    	<tx:method name="方法名,可以为不同的方法设置事务参数" isolation="事务隔离级别" propagation="事务传播行为" timeout="超时时长" read-only="只读"></tx:method>
    </tx:attributes>
</tx:advice>


<aop:config>
	<aop:advisor advice-ref="txAdvice" pointcut="切点"/>
</aop:config>
注解版 注解驱动
<tx:annotation-driven/> 
@EnableTransactionManagement
找到切点,@Transactional(isolation="事务隔离级别",propagation="事务传播行为",timeout="超时时长",read-only="只读",transaction-manager="指定事务管理器")
posted @ 2020-06-14 14:12  shiroshiro  阅读(376)  评论(0)    收藏  举报