IOC
IOC称为控制反转,在此过程中,对象仅通过构造函数参数、工厂方法参数或在对象实例被构造或从工厂方法返回后设置的属性来定义它们的依赖项。然后容器在创建bean时注入这些依赖项。从根本上说,这个过程是bean本身通过直接构造类来控制依赖项的实例化的相反过程,因此得名控制反转。
IOC的Maven依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.3.6</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.6</version>
</dependency>
IOC容器
applicationcontext
接口表示IOC容器,它通过加载配置元数据来实例化、配置和组装bean。以下是它的重要实现:
- ClassPathXmlApplicationContext:它可以加载类路径下的xml配置文件
- FileSystemXmlApplicationContext:它可以加载磁盘任意路径下的xml配置文件
- AnnotationConfigApplicationContext:它可以加载注解配置类
bean
在容器本身内,bean被表示为BeanDefinition
对象。IOC加载的元数据会存储在该对象内。
id和name
id和name属性用于指定bean的标识符,唯一的区别在于name可以指定多个标识符,而id只能指定一个。
<bean id="id" name="name1 name2"/>
class
class用于指定bean类型。
<bean class=“className”/>
当通过构造函数创建bean时,class的值为要构造的bean的全限定类名,这在某种程度上相当于带有new操作符的Java代码。
<bean id="beanId" class="examples.ExampleBean"/>
当通过静态工厂方法创建bean时,class的值为包含静态工厂方法类的全限定类名,并使用名为factory-method的属性指定工厂方法本身的名称。
<bean id="clientService" class="examples.ClientService" factory-method="createInstance"/>
当通过非静态工厂方法创建bean时,将class属性保留为空,并在factory-bean属性中指定包含要被调用来创建对象的实例方法的非静态工厂,最后使用factory-method属性设置工厂方法本身的名称。
<bean id="clientService" factory-bean="serviceLocator" factory-method="createClientServiceInstance"/>
<bean id="serviceLocator" class="examples.DefaultServiceLocator"/>
scope
scope有两层含义:
- 第一:这个bean会被实例化几次
- 第二:bean存活的时间
<bean id="beanId" class="examples.ExampleBean" scope=“scopeValue”/>
scopeValue | 说明 |
---|---|
singleton(默认) | 一个bean对应IOC容器中的一个对象 |
prototype | 一个bean对应IOC容器中的多个对象 |
request | 一个bean对应request生命周期中的一个对象 |
session | 一个bean对应session生命周期中的一个对象 |
application | 一个bean对应ServletContext生命周期中的一个对象 |
websocket | 一个bean对应每个websocket生命周期中的一个对象 |
lazy-init
默认情况下IOC容器会在启动时实例化所有bean,但是可以使用懒加载模式禁止这一行为,让bean在使用时才实例化。
<bean id="lazy" class="com.something.ExpensiveToCreateBean" lazy-init="true"/>
init-method
<bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>
destroy-method
<bean id="exampleInitBean" class="examples.ExampleBean" destroy-method="cleanup"/>
Bean生命周期
Bean的生命周期是指从Bean对象创建到销毁的过程
- 实例化
- 依赖注入
- 初始化方法
- 使用
- 销毁方法
依赖注入
依赖注入是一个过程,对象通过构造函数参数、工厂方法的参数或在对象实例被构造或从工厂方法返回后设置的属性来定义它们的依赖项。然后,容器在创建bean时注入这些依赖项。
注入方式
构造函数注入
基于构造函数的依赖注入是通过容器调用带有许多参数的构造函数来完成的,每个参数表示一个依赖项。如果bean定义的构造函数参数中不存在潜在的歧义,那么<constructor-arg>
的顺序就是在实例化bean时将这些参数提供给适当的构造函数的顺序。大部分情况都应该使用基于构造函数的依赖注入。
<beans>
<bean id="beanOne" class="x.y.ThingOne">
<constructor-arg ref=""/>
<constructor-arg name="" value=""/>
<constructor-arg type="" value=""/>
</bean>
</beans>
<constructor-arg>
有以下常用属性。
属性 | 说明 |
---|---|
type | 当构造参数为基本类型、Spring等一些不能确定的值类型时,就需要此指定它们的类型。 |
name | name属性用于指定构造函数参数名。 |
ref | ref属性用于指定一个已在容器中的bean |
setter注入
基于setter的依赖注入是通过容器在调用无参数构造函数或无参数静态工厂方法来实例化bean之后调用bean上的setter方法来完成的。基于setter的注入应该只用于可选依赖项,这些依赖项可以在类中分配合理的默认值。
<bean id="exampleBean" class="examples.ExampleBean">
<property name="beanOne">
<ref bean="anotherExampleBean"/>
</property>
<property name="beanTwo" ref="yetAnotherBean"/>
<property name="integerProperty" value="1"/>
</bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
方法注入
方法注入用于解决实例化次数不同bean之间的依赖问题。比如一个singleton
依赖一个prototype
,这会导致后者只会被注入一次。但是当前版本可以直接注入一个ApplicationContext
来解决这个问题。
public class Student {
@Autowired
private ApplicationContext applicationContext;
private Teacher teacher;
public Teacher getTeacher() {
teacher=applicationContext.getBean(Teacher.class);
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
}
public class Teacher {
public static int count;
public Teacher() {
count++;
}
}
代理注入
代理注入用于解决存活时间不同bean之间的依赖问题。比如一个singleton
依赖一个request
,后者在每次请求都会被创建一次,但是只会被注入一次。
<bean id="userPreferences" class="com.something.UserPreferences" scope="request">
<aop:scoped-proxy/>
</bean>
<bean id="userManager" class="com.something.UserManager">
<property name="userPreferences" ref="userPreferences"/>
</bean>
循环依赖
当使用构造函数注入时,可能会创建无法解决的循环依赖场景。例如:A类通过构造函数注入需要B类的实例,B类通过构造函数注入需要A类的实例。如果您将类A和B的bean配置为相互注入,则IOC容器在运行时检测到此循环引用,并抛出一个 BeanCurrentlyInCreationException
。一种可能的解决方案是编辑一些类的源代码,以便由 setter 而不是构造函数来配置。或者,避免构造函数注入并仅使用 setter 注入。
注入类型
字面量
<constructor-arg name="years" value="7500000"/>
<property name="integerProperty" value="1"/>
bean
ref注入
<constructor-arg name="beanTwo" ref="yetAnotherBean"/>
<property name="beanTwo" ref="yetAnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
内部bean
<bean id="outer" class="...">
<property name="target">
<bean class="com.example.Person">
<property name="name" value="Fiona Apple"/>
<property name="age" value="25"/>
</bean>
</property>
</bean>
级联注入
<bean id="something" class="things.ThingOne">
<property name="fred.bob.sammy" value="123" />
</bean>
自动装配
Spring容器可以自动装配协作bean之间的关系。
<bean id="yetAnotherBean" class="examples.YetAnotherBean" autowire="autowireMode"/>
自动装配有以下几种模式:
autowireMode | 说明 |
---|---|
no(默认) | 没有自动装配。Bean引用必须由ref元素定义。 |
byName | 通过属性名自动装配。 |
byType | 通过是属性类型进行装配,如果容器中有一个相同类型的bean,则自动注入属性。如果存在多个类型相同的bean,则抛出异常。如果没有相同类型的bean,则不会进行依赖注入。 |
constructor | 类似于byType,但应用于构造函数参数。不同之处在于如果容器中没有一个类型相同的bean,则会报错。 |
值得注意的是property
和constructor-arg
设置中的显式依赖项始终覆盖自动装配。我们不能自动装配简单属性,例如基元本类型、String 、Classes以及这些简单的数组。
depends-on
在bean之间的依赖关系不是特别明显时可以使用depends-on
。比如说加载数据库的驱动文件。
<bean id="beanOne" class="ExampleBean" depends-on="manager,accountDao"/>
<bean id="manager" class="ManagerBean" />
<bean id="accountDao" class="x.y.jdbc.JdbcAccountDao" />
集合注入
数组注入
<array>
<value>aaa</value>
<ref bean=""></ref>
</array>
list注入
<list>
<value>qqq</value>
<ref bean=""></ref>
</list>
map注入
<map>
<entry key="1" value="hh"></entry>
<entry key="2">
<value>www</value>
</entry>
</map>
set注入
<set>
<value>haha</value>
<ref bean=""></ref>
</set>
property注入
<props>
<prop key="key">value</prop>
</props>
集合合并
子集合可以继承或覆盖父集合中的内容。
<beans>
<bean id="parent" abstract="true" class="example.ComplexObject">
<property name="adminEmails">
<props>
<prop key="administrator">administrator@example.com</prop>
<prop key="support">support@example.com</prop>
</props>
</property>
</bean>
<bean id="child" parent="parent">
<property name="adminEmails">
<!-- the merge is specified on the child collection definition -->
<props merge="true">
<prop key="sales">sales@example.com</prop>
<prop key="support">support@example.co.uk</prop>
</props>
</property>
</bean>
<beans>
null和空字符串
空字符串
<bean class="ExampleBean">
<property name="email" value=""/>
</bean>
null
<bean class="ExampleBean">
<property name="email">
<null/>
</property>
</bean>
整合其它配置文件
<import resource="resourceName"></import>
IOC相关注解
使用注解前应在配置文件中加入以下标签来注册注解处理器:
<context:annotation-config/>
@Component
@Component注解用于向IOC容器中注册bean,它还有以下三个兄弟注解:
注解 | 说明 |
---|---|
@Controller | 用于标识在控制层上 |
@Service | 用于标识在服务层上 |
@Repository | 用于表示在持久层上. |
使用此类注解时需要在配置文件中开启自动扫描功能:
<context:component-scan base-package="org.example">
<context:include-filter type="regex"expression=".*Stub.*Repository"/>
<context:exclude-filter type="annotation"expression="org.springframework.stereotype.Repository"/>
</context:component-scan>
值得注意的是使用该标签隐式开启了 <context:annotation-config>
标签的功能,所以它们不应该同时存在。
@Scope
@Scope注解用于指定bean的范围。
String value() default "";
String scopeName() default "";
@Autowired
@Autowired注解按照依赖类型进行自动注入,它可以用在构造函数、setter方法或直接放在字段上。
public class Student {
@Autowired
private Teacher teacher;
@Autowired
public Student(Teacher teacher) {
this.teacher = teacher;
}
public Teacher getTeacher() {
return teacher;
}
@Autowired
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
}
如果将此注解放在集合或数组类型上,它可以将所有同类型的bean都注入到集合或数组中。在注入到Map中时,bean的id或那么属性作为键,bean作为值。如果想要控制他们在集合或数组中的位置,可以实现Ordered
接口或使用@Order
注解。
public class Student {
@Autowired
private Map<String,Teacher> teacherMap;
public Map<String, Teacher> getTeacherMap() {
return teacherMap;
}
public void setTeacherMap(Map<String, Teacher> teacherMap) {
this.teacherMap = teacherMap;
}
}
默认情况下,当注入点没有匹配的bean时,自动装配会失败。这是由于它的required属性默认为true,在使用时可以将其设置为false。如果一个类有多个构造函数都使用了此注解,那么其中只能有一个注解的required属性为true。
boolean required() default true;//是否必要
@Qualifier
在使用@Autowired注解时,当注入点有多个匹配的bean就会出现异常,此时可以用
@Autowired注解进行微调,它可以指定一个限定值来精确匹配bean。
String value() default "";//指定限定值
在默认情况下,限定值为bean的id或name属性值。也可以通过以下方式指定一个限定值:
<bean class="example.SimpleMovieCatalog">
<qualifier value="main"/>
</bean>
@Resource
@Resource按照bean的id或name属性值进行注入。它可以用在构造函数、setter方法或直接放在字段上。如果在使用注解时没有指定它的name属性,则默认名称源自字段名称或 setter 方法。如果是字段,则使用字段名称。在 setter 方法的情况下,它采用 bean 属性名称。
String name() default "";//指定名称
@Value
@Value注解用于注入字面量值或外部属性,它往往与EL表达式一起使用。它可以用在方法、字段和方法参数上。
String value();//指定值
当value值为EL表达式时但没有数据与之匹配,此时就会将EL表达式作为字符串注入,可以添加一个配置类来解决这个问题:
@Configuration
public class AppConfig {
@Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
@PostContstruct和@PreDestroy
@PostContstruct注解用于指定初始化方法。@PreDestroy注解用于指定bean销毁方法。
public class CachingMovieLister {
@PostConstruct
public void populateMovieCache() {
// populates the movie cache upon initialization...
}
@PreDestroy
public void clearMovieCache() {
// clears the movie cache upon destruction...
}
}
环境抽象
每一个IOC容器都有一个Environment
抽象类的实现类,它描述了应用程序的概要文件和属性信息。
概要文件
概要文件是一组bean的定义,只有在概要文件处于活跃状态时,这些bean才被注入到容器中。通过设控制要文件何时处于活跃状态就可以将应用程序部署到不同的环境中,比如开发环境、测试环境以及生产环境。
@Profile
@Configuration
public class ApplicationConfiguration {
@Bean(name = "teacher")
@Profile("default")
public Teacher defaultTeacher(){
return new Teacher("default");
}
@Bean(name = "teacher")
@Profile("product")
public Teacher productTeacher(){
return new Teacher("product");
}
@Bean(name = "teacher")
@Profile("test")
public Teacher testTeacher(){
return new Teacher("test");
}
}
激活
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.getEnvironment().setActiveProfiles("test");
context.register(ApplicationConfiguration.class);
context.refresh();
属性
属性就是应用程序需要的配置信息,它们可以来源于任何文件。
<context:property-placeholder location="jdbc.properties"></context:property-placeholder>
使用springEL表达式过去文件中的值:
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
</bean>
也可以使用@PropertySource
注解该注解用于导入外部键值对配置文件,常与@Value搭配使用。
@Target({ElementType.TYPE})
String[] value();
Resource
SQEL
AOP
AOP称为面向切面编程,简单的说它就是把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对我们的已有方法进行增强。AOP在默认情况下使用JDK基于接口的动态代理。本文AOP部分涉及的内容不多,详情见官网。
AOP的Maven依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
AOP的相关术语
术语 | 说明 |
---|---|
Joinpoint(连接点) | 能够被增强的方法 |
Pointcut(切入点) | 实际被增强的方法 |
Advice(通知) | 通知是指实际增强的具体内容 |
Aspect(切面) | 存放通知的类 |
Target(目标对象) | 代理的目标对象 |
Proxy(代理) | 一个类被 AOP 织入增强后,就产生一个结果代理类。 |
切入点表达式
切入点表达式的作用是指定切入点,也就是指定对哪些方法进行增强。
execution(访问修饰符 返回值 全限定类名.方法名(参数类型))
访问修饰符 | 可以省略 |
返回值 | 可以使用*号,表示任意返回值 |
全限定类名 | 可以使用*号,表示任意类 |
方法名 | 可以使用*号,表示任意方法 |
参数列表 | 1、可以直接写数据类型 2、可以使用*,表示参数可以是任意数据类型 3、可以使用…表示有无参数均可,有参数可以是任意类型 |
通知
- 前置通知:在连接点之前运行但不能阻止执行流继续到连接点的通知(除非它抛出异常)。
- 后置通知:在连接点正常完成后运行的通知(例如,如果方法返回而不引发异常)。
- 异常通知:在连接点抛出异常退出时运行的通知。
- 最终通知:不管连接点以何种方式退出(正常或异常返回),都要运行的通知。
- 环绕通知:可以在方法调用前后执行自定义行为。它还负责选择是继续到连接点,还是通过返回自己的返回值或抛出异常。一般不建议使用。
<aop:config>
<aop:pointcut id="businessService" expression="execution(* com.xyz.myapp.service.*.*(..))"/>
<aop:aspect id="myAspect" ref="aBean">
<aop:before pointcut-ref="businessService" method="monitor"/>
<aop:after-returning pointcut-ref="dataAccessOperation" method="doAccessCheck"/>
<aop:after-throwing pointcut-ref="dataAccessOperation" method="doRecoveryActions"/>
<aop:after pointcut-ref="dataAccessOperation" method="doReleaseLock"/>
</aop:aspect>
</aop:config>
<bean id="aBean" class="..."/>
AOP相关注解
使用AOP注解之前应先开启注解支持:
<aop:aspectj-autoproxy/>
@Aspect
将当前类声明为切面类。
String value() default "";
@Pointcut
配置公共切入点。
String value() default "";//切入点表达式
String argNames() default "";
@Before
把当前方法指定为前置通知。
String value();//切入点表达式
String argNames() default "";
@AfterReturning
把当前方法指定为后置通知。
String value() default "";//切入点表达式
String pointcut() default "";//切入点表达式
String returning() default "";//切入点的返回值,当切入点返回时,返回值会自动注入到通知参数的同名参数中
String argNames() default "";
@AfterThrowing
把当前方法指定为异常通知。
String value() default "";//切入点表达式
String pointcut() default "";//切入点表达式
String throwing() default "";//切入点抛出的异常,当切入点抛出异常时,异常对象会自动注入到通知参数的同名参数中
String argNames() default "";
@After
把当前方法指定为环绕通知。
String value();//切入点表达式
String argNames() default "";
事务管理
在java中有以下两种事务:
- 全局事务:资源管理器管理和协调的事务,可以跨越多个数据库和进程。服务器通过JTA对全局事务进行管理。它使用的条件很多并且API极为复杂。
- 本地事务:本地事务是特定于资源的,例如与JDBC连接关联的事务。本地事务可能更容易使用,它的缺点是不能跨多个事务资源工作。
Spring事务完美解决了全局事务和本地事务的缺点,它允许应用程序开发人员在任何环境中使用一致的编程模型。并且提供了声明式和程序化的事务管理。
事务管理的Maven依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.3.6</version>
</dependency>
TransactionManager
TransactionManager定义了事务的策略,事物的策略是事务抽象的关键。PlatformTransactionManager是TransactionManager的一个子接口,它用于命令式管理事务。
public interface PlatformTransactionManager extends TransactionManager {
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}
getTransaction()方法通过一个TransactionDefinition(该接口定义了事务的基本信息:传播性、隔离级别、超时时常和事务状态。)对象获取一个TransactionStatus对象。TransactionStatus接口为事务代码提供了一种简单的方法来控制事务执行和查询事务状态。
public interface TransactionStatus extends TransactionExecution, SavepointManager, Flushable {
@Override
boolean isNewTransaction();
boolean hasSavepoint();
@Override
void setRollbackOnly();
@Override
boolean isRollbackOnly();
void flush();
@Override
boolean isCompleted();
}
声明式事务
声明式事务是springAOP最重要的实现功能。
<tx:advice>
该标签用于配置事务通知,它的默认配置如下:
- 传播性:REQUIRED
- 隔离级别:DEFAULT
- 事务状态:read-write
- 超时:与基础事务系统的默认超时相同
<tx:method>
属性 | 谁否必须 | 默认值 | 说明 |
---|---|---|---|
name | Yes | - | 事务属性要与之关联的方法名 |
propagation | No | REQUIRED | 传播性 |
isolation | No | DEFAULT | 隔离级别 |
timeout | No | -1 | 超时 |
read-only | No | false | 事务状态 |
rollback-for | No | - | 触发回滚的以逗号分隔的异常实例列表 |
no-rollback-for | No | - | 未触发回滚的以逗号分隔的异常实例列表 |
demo
package x.y.service;
public interface FooService {
Foo getFoo(String fooName);
Foo getFoo(String fooName, String barName);
void insertFoo(Foo foo);
void updateFoo(Foo foo);
}
package x.y.service;
public class DefaultFooService implements FooService {
@Override
public Foo getFoo(String fooName) {
// ...
}
@Override
public Foo getFoo(String fooName, String barName) {
// ...
}
@Override
public void insertFoo(Foo foo) {
// ...
}
@Override
public void updateFoo(Foo foo) {
// ...
}
}
要求前两个方法在读事务中进行,后两个方法在写事务中进行。
<!-- from the file 'context.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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 这是我们想让它成为事务性的服务对象-->
<bean id="fooService" class="x.y.service.DefaultFooService"/>
<!-- 事务建议-->
<tx:advice id="txAdvice" transaction-manager="txManager">
<!-- 事务属性 -->
<tx:attributes>
<!-- 所有以'get'开头的方法都是只读的 -->
<tx:method name="get*" read-only="true"/>
<!-- 其他方法使用默认事务设置-->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!-- 切面定义 -->
<aop:config>
<aop:pointcut id="fooServiceOperation" expression="execution(* x.y.service.FooService.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation"/>
</aop:config>
<!-- 配置数据源 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:@rj-t42:1521:elvis"/>
<property name="username" value="scott"/>
<property name="password" value="tiger"/>
</bean>
<!-- 配置事务管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
事务回滚
当处在事务执行上下文的方法出现异常时会导致事务回滚,默认设置非受查导致回滚受查异常不导致事务回滚。我们可以手动设置触发事务回归异常的类型,这个类型可以是受查异常和非受查异常。
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="get*" read-only="true" rollback-for="NoProductInStockException"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
事务的传播性
PROPAGATION_REQUIRED
该值会使当前事务通知使用最外层的事务,比如在事务通知1中调用事务通知2,事务通知2并不会创建一个新事务而是会继续使用事务通知1创建的事务。那么此时就会忽略在事务通知2内设置的隔离级别、事务状态和超时时间。
PROPAGATION_REQUIRES_NEW
该值会使当前事务通知处于一个新的事务,而不参与其它外层事务。比如在事务通知1中调用事务通知2,事务通知2会创建一个新的事务,此时transaction1会挂起等待transaction2结束。
PROPAGATION_NESTED
该值使用带有多个保存点的单个物理事务,它可以回滚到这些保存点。这样外层失败时会回滚内层事务所作的动作,而内层回滚时并不会引起外部事务的回滚。
@Transactional
可以使用此注解代替xml进行事务配置。当此注解在方法桑上时,该方法应该具有公共可见性。
@Target({ElementType.TYPE, ElementType.METHOD})
属性 | 属性值 | 说明 |
---|---|---|
value | “” | 事务管理器的名称 |
propagation | Propagation.REQUIRED:使用调用者的事务,默认属性值 Propagation.REQUIRES_NEW:使用被调用者的事务 | 控制事务的传播 |
isolation | Isolation.DEFAULT:与数据库的默认提交方式相同 Isolation.READ_UNCOMMITTED:读未提交 Isolation.READ_COMMITTED读已提交 Isolation.REPEATABLE_READ:可重复读 Isolation.SERIALIZABLE串行化 | 设置事务的隔离级别 |
timeout | int型秒数 | 设置在事务强制回滚前可以等待的时间 |
readOnly | 默认为false | 指定当前事务中所有的操作是否为只读,若设置为只读mysql就会在数据访问的时候不加锁提高性能 |
rollbackFor | 异常字节码文件 | 设置当发生什么异常时事务回滚 |
rollbackForClassName | 异常全限定类名 | 同上 |
noRollbackFor | 异常字节码文件 | 设置当发生什么异常时事务不应该回滚 |
noRollbackForClassName | 异常全限定类名 | 同上 |
完全注解开发
@Configuration
使用此注解的类为配置类,表示该类的主要目的是作为 Bean 定义的来源。
@Target({ElementType.TYPE})
boolean proxyBeanMethods() default true;
proxyBeanMethods
参数用于设置配置类中的方法是不是代理方法,如果是true那么这些方法是代理方法,那么每次我们手动调用这些方法获取bean时Spring会检查容器中有没有这个类型的bean,如果有就返回,没有就创建;如果是false,那么Spring不会检查,每次调用方法都会返回一个新的。
@Import
@Import用于导入其它配置类。
@Target({ElementType.TYPE})
Class<?>[] value();
@ImportResource
@ImportResource注解用于导入其它xml配置文件。
@Target({ElementType.TYPE})
String[] value() default {};
@ComponentScan
此注解用于自动检测构bean造型类,并向ApplicationContext注册相应的BeanDefinition实例。
@Target({ElementType.TYPE})
String[] value() default {};//基础包
String[] basePackages() default {};//基础包
ComponentScan.Filter[] includeFilters() default {};//包含过滤器
ComponentScan.Filter[] excludeFilters() default {};//移除过滤器
@Filter
过滤器。
FilterType type() default FilterType.ANNOTATION;//过滤器类型
Class<?>[] value() default {};//指定过滤注解类
Class<?>[] classes() default {};//指定过滤注解类
String[] pattern() default {};//指定表达式
过滤器类型 | 说明 |
---|---|
annotation | 在目标组件的类型级别上存在的 注解。 |
assignable | 目标组件可分配给(扩展或实现)的类(或接口)。 |
aspectj | 目标组件要匹配的 AspectJ 类型表达式。 |
regex | 要与目标组件类名称匹配的正则表达式。 |
custom | org.springframework.core.type .TypeFilter接口的自定义实现。 |
@Bean
@Bean注解可以将配置类中方法的返回值注册到容器中。如果没有指定name属性那么bean的id默认为方法名。
String[] value() default {};//bean标识符
String[] name() default {};//bean标识符
boolean autowireCandidate() default true;//支持自动装配
String initMethod() default "";//初始化方法
String destroyMethod() default "(inferred)";//销毁方法
可以将@Bean方法声明为static,从而允许在不将其包含的配置类创建为实例的情况下调用它们。此类 bean在容器生命周期的早期被初始化,因此应避免在此时触发配置的其他部分。在配置类中的常规@Bean方法需要重写也就是说,它们不能声明为private或final。
@Conditional
@Conditional可以有条件地启用或禁用一个完整的@Configuration类,甚至单个的@Bean方法。
Class<? extends Condition>[] value();//注入的条件
@EnableAspectJAutoProxy
@EnableAspectJAutoProxy注解用于开启AspectJ注解支持。
@Target({ElementType.TYPE})
@EnableTransactionManagement
@EnableTransactionManagement注解用于开启事务支持。
@Target({ElementType.TYPE})