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="指定事务管理器")

浙公网安备 33010602011771号