先介绍下面经常使用的beanDefinition,这个类装载了bean的信息,比如名字,是否单例,作用范围,bean的类型,是否延迟加载等诸多信息
@Configuration
spring配置注解
注册一个bean
@Bean
@Bean
public FaBean gatFabean(){
System.out.println("gatFabean:我被创建了");
return new FaBean();
}
@Scope和@Lazy
指定bean以单例还是多例,单例:singleton 多例:prototype ,默认单例
在单例模式下,spring默认使用的是饿汉式加载,而多例模式用的是懒加载,也就是在容器创建的过程中就会把容器中组件实例创建出来,可以使用@Lazy变为懒加载,就是创建容器时不加载实例,在调用过程中才创建实例,懒加载只针对单例模式
- @Scope
@Configuration
@ComponentScan(value = "com.example.springLearn.newlearn")
public class SpringConfig {
//设置多例模式
@Scope("prototype")
@Bean
public User getuser(){
return new User(1,"james");
}
}
@org.junit.Test
public void test2(){
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig.class);
User user=(User) ac.getBean("getuser");
User user2=(User) ac.getBean("getuser");
System.out.println(user==user2?true:false);
}

去掉 @Scope("prototype")后
//@Scope("prototype")
@Bean
public User getuser(){
return new User(1,"james");
}

-
@Lazy
默认模式下创建容器,并且不调用bean,只是创建spring容器,控制台有了输出,说明spring创建的同时调用了getuser()去创建了user实例
@Bean
public User getuser(){
System.out.println("我被创建了");
return new User(1,"james");
}
@org.junit.Test
public void test2(){
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig.class);
}

使用懒加载,创建容器时,控制台没有输出,调用组件才有输出
@Bean
@Lazy
public User getuser(){
System.out.println("我被创建了");
return new User(1,"james");
}

@ComponentScan 包扫描
1、excludeFilters 排除掉指定的类、includeFilters只包含指定的类(只包含需设置useDefaultFilters = false)
-
FilterType.ANNOTATIONilterType.ANNOTATION
指定扫描的注解
//排除扫描到的Controller注解
@Configuration
@ComponentScan(excludeFilters = {
@ComponentScan.Filter(type= FilterType.ANNOTATION,classes = {Controller.class})
},value = "com.example.springLearn.newlearn")
public class SpringConfig {
}
测试
@org.junit.Test
public void test1(){
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig.class);
//获取容器中的组件
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}

-
FilterType.ASSIGNABLE_TYPE
指定扫描的类型
@Configuration
@ComponentScan(excludeFilters = {
@ComponentScan.Filter(type= FilterType.ANNOTATION,classes = {Controller.class}),
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = {ServiceTest.class})
},value = "com.example.springLearn.newlearn")
public class SpringConfig {
}
测试结果

-
FilterType.CUSTOM
自定义过滤器
public class MyFilter implements TypeFilter {
/**
* @param metadataReader :读取正在扫描的信息
* @param metadataReaderFactory 获取到其他任何类信息
* @return
* @throws IOException
*/
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
//获取当前类注解信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
//获取当前正在扫描的类的信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
//获取当前类路径
Resource resource = metadataReader.getResource();
System.out.println(resource.getURI());
System.out.println(classMetadata.getClassName());
//组件中包含Service的都会放行
if (classMetadata.getClassName().contains("Service")){
return true;
}
return false;
}
}
@Configuration
@ComponentScan(excludeFilters = {
@ComponentScan.Filter(type = FilterType.CUSTOM,classes = {MyFilter.class})
},value = "com.example.springLearn.newlearn")
public class SpringConfig {
}

@Conditional
按照条件进行装配,放类上时需要满足条件才可以进行装配类下的注册配置,放在方法上时需要满足条件才可以装配方法下的注册配置,springboot大量使用这个注解进行条件装配
@Bean
@Lazy
public User getuser(){
System.out.println("getuser:我被创建了");
return new User(1,"james");
}
@Conditional(ConditionConstom.class)//按照条件进行注册 springboot大量使用的注解
@Bean
public User getuser2(){
System.out.println("getuser2:我被创建了");
return new User(1,"kobe");
}
public class ConditionConstom implements Condition {
/**
*
* @param conditionContext:判断上下文环境
* @param annotatedTypeMetadata
* @return
*/
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
//获取当前环境信息
Environment environment = conditionContext.getEnvironment();
//获取ioc的创建工厂
ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
//获取注册类
BeanDefinitionRegistry registry = conditionContext.getRegistry();
//判断容器中是否注册了getuser这个bean
//注册了getuser就手动注册一个conditionDog的bean
if (registry.containsBeanDefinition("getuser")){
Class<Dog> dogClass = Dog.class;
Field[] declaredFields = dogClass.getDeclaredFields();
MutablePropertyValues mv=new MutablePropertyValues();
for (Field declaredField : declaredFields) {
if (declaredField.getName().equals("name")){
mv.add(declaredField.getName(),"conditionDogname");
}
if (declaredField.getName().equals("id")){
mv.add(declaredField.getName(),1);
}
}
BeanDefinition beanDefinition=new RootBeanDefinition(Dog.class,null,mv);
//手动注册一个conditionDog的bean
registry.registerBeanDefinition("conditionDog",beanDefinition);
Dog dogbean = (Dog) beanFactory.getBean("conditionDog");
System.out.println("我注册了conditionDog,");
System.out.println(dogbean.toString());
return true;
}
return false;
}
}

@Import
快速注册一个bean
@Configuration
@ComponentScan(value = "com.example.springLearn.newlearn")
@Import({Cat.class})
public class SpringConfig {
...............
测试
@org.junit.Test
public void test1(){
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig.class);
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}
我们看到返回的bean的名字是类的全路径

同时可以通过自定义类进行注册
@Configuration
@ComponentScan(value = "com.example.springLearn.newlearn")
@Import({Cat.class, MySelector.class})
public class SpringConfig {
...............
自定义
public class MySelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
return new String[]{"com.example.springLearn.newlearn.bean.Hive","com.example.springLearn.newlearn.bean.Spark"};
}
}

FactoryBean类注入
通过实现FactoryBean类可以向容器注册组件,
public class FaBean implements FactoryBean<Php> {
//注册的bean实例
@Override
public Php getObject() throws Exception {
return new Php(1,"php");
}
//注册的bean的类型
@Override
public Class<?> getObjectType() {
return Php.class;
}
//定义是是否为单例,true是,false否
@Override
public boolean isSingleton() {
return true;
}
}
@Bean
public FaBean gatFabean(){
System.out.println("gatFabean:我被创建了");
return new FaBean();
}
BeanDefinitionRegistryPostProcessor 和 ImportBeanDefinitionRegistrar
通过实现BeanDefinitionRegistryPostProcessor 的postProcessBeanDefinitionRegistry方法注册一个bean
@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
RootBeanDefinition rootBeanDefinition=new RootBeanDefinition();
rootBeanDefinition.setBeanClass(Hadoop.class);
registry.registerBeanDefinition("hadoop",rootBeanDefinition);
System.out.println("MyBeanDefinitionRegistryPostProcessor:postProcessBeanDefinitionRegistry===============");
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("MyBeanDefinitionRegistryPostProcessor:postProcessBeanFactory===============");
}
}
通过实现ImportBeanDefinitionRegistrar 的registerBeanDefinitions方法注册一个bean
@Component
public class MyImportBeanDefinitionRegistry implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
RootBeanDefinition rootBeanDefinition=new RootBeanDefinition();
rootBeanDefinition.setBeanClass(Hadoop.class);
registry.registerBeanDefinition("hadoop2",rootBeanDefinition);
System.out.println("MyBeanDefinitionRegistryPostProcessor:postProcessBeanDefinitionRegistry===============");
}
}
生命周期
@Bean
使用@Bean指定的生命周期
@Bean(initMethod = "init",destroyMethod = "die")
public Dog dog(){
return new Dog();
}
@Data
public class Scala {
private int id;
private String name;
public Scala() {
System.out.println("scala的空参构造函数执行..........");
}
public void init() {
System.out.println("init........");
}
public void die() {
System.out.println("destory........");
}
}
先执行空参构造,然后容器销毁时在调用die()

@PostConstruct和@PreDestroy
注入容器的组件中的方法使用了@PostConstruct后将在容器初始化组件后被调用,注入容器的组件中的方法使用了@PreDestroy后将在容器销毁前被调
@Data
@Component
public class Html {
private Integer id;
private String name;
public Html(Integer id, String name) {
this.id = id;
this.name = name;
}
public Html() {
System.out.println("html调用了构造方法");
}
//@PostConstruct在容器的组件初始化后使用
@PostConstruct
public void post(){
System.out.println("Html调用了@PostConstruct的方法");
}
//@PreDestroy在容器的组件被摧毁前被调用
@PreDestroy
public void destroy(){
System.out.println("Html调用了@PreDestroy的方法");
}
}
BeanPostProcessor 后置处理器
内置的postProcessBeforeInitialization方法是在容器的bean开始初始化后调用,postProcessAfterInitialization方法在容器的bean初始后完成后调用
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println(beanName+"开始初始化了.......");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println(beanName+"初始化完成了.......");
return bean;
}
}

可以看到bean的后置处理器的postProcessBeforeInitialization方法是在bean的初始化开始后执行的并且是比@PostConstruct提前执行,这是postProcessBeforeInitialization和@PostConstruct的区别,postProcessAfterInitialization是在bean执行完初始后执行的
文件加载和成员变量设值
@PropertySource加载配置文件
@Value设值成员变量的值:
@Value("${rabbitmq.id}")将从配置文件中设值,@Value("#{5673-1}")利用EL表达式进行计算设值, @Value("我的virtualHost")常量设值
加载classpath下的配置文件
@Configuration
@PropertySource("classpath:/myApplication.properties")
@ComponentScan(value = "com.example.springLearn.newlearn")
public class RabbitMqConfig {
@Value("${rabbitmq.id}")
private String ip;
@Value("#{5673-1}")
private int port;
@Value("${rabbitmq.username}")
private String username;
@Value("${rabbitmq.password}")
private String password;
@Value("我的virtualHost")
private String virtualHost;
@Bean
public RabbitMq gatRabbbitMq(){
try {
RabbitMq rabbitMq=new RabbitMq(ip,port,username,password,virtualHost);
return rabbitMq;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}

rabbitmq.id=127.0.0.1
rabbitmq.port=5672
rabbitmq.username=guest
rabbitmq.password=guest
rabbitmq.virtualHost=testhost
@org.junit.Test
public void test4(){
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(RabbitMqConfig.class);
RabbitMq bean = ac.getBean(RabbitMq.class);
System.out.println(bean.toString());
ac.close();
}

自动装配
spring的规范:
@Autowired 按照类型自动注入
@Qualifier("xxxx") 强行按照指定的名称自动注入
@Primary 将标注@Primary的方法的bean变为默认注入
优先级@Autowired <@Primary<@Qualifier("xxxx")
默认按照类型去容器找相应的组件,如果找到就赋值,如果存在多个类型的组件,就选择组件名称是申明等待赋值的引用名称的那个组件注入,如果使用了@Qualifier可以强行指定使用指定名称的那个类型或者使用@Primary优先首选注入,如果申明的@Service,@Component,@Controller没有指明bean的名称,则按照类名称的首字母小写注入
@Autowired(require=false)还可以设置属性,表明能在容器中找到这个组件就赋值,找不到就算了,也不会报错
@Service
@Data
public class Kafka {
private String name="kafka";
public void say(){
System.out.println("我是"+name);
}
}
@Bean("kafka2")
public Kafka gatKafka(){
Kafka kafka = new Kafka();
kafka.setName("kafka2");
return kafka;
}


@Controller
public class TestController {
@Autowired
private Kafka kafka;
public void test(){
kafka.say();
}
}

@Controller
public class TestController {
@Autowired
private Kafka kafka2;
public void test(){
kafka2.say();
}
}

@Controller
public class TestController {
@Qualifier("kafka")
@Autowired
private Kafka kafka2;
public void test(){
kafka2.say();
}
}

@Primary
@Bean("kafka2")
public Kafka gatKafka(){
Kafka kafka = new Kafka();
kafka.setName("kafka2");
return kafka;
}
@Controller
public class TestController {
//@Qualifier("kafka")
@Autowired
private Kafka kafka;
public void test(){
kafka.say();
}
}

java的规范:
@Resource 默认按照引用名称注入,@Primary和@Qualifier将不起效果,可以通过@Resource(name="xxxx")指定注入哪个组件,这个的功能比较少,还是别花里胡哨的了,乖乖用@Autowired把
XXXXXXAware方法:实现了XXXXXXAware方法后可以在创建对象时,对象初始化前会调用接口规定的方法注入组件
@Component
public class TestService implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext=applicationContext;
System.out.println("setApplicationContext被调用了");
}
public String test(){
return applicationContext.getEnvironment().getProperty("key1");
}
}

Spring的后置处理器
BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor
BeanFactoryPostProcessor是BeanFactory的后置处理器,是在BeanFactory标准初始化之后才会被调用后置处理方法,也就是在BeanFactory保存了所有bean的定义后,才会调用,注意此时只是保存bean的定义信息,例如名字,但是还没有真正的创建对象。BeanDefinitionRegistryPostProcessor 继承自 BeanFactoryPostProcessor,比 BeanFactoryPostProcessor 具有更高的优先级,主要用来在常规的BeanFactoryPostProcessor 检测开始之前注册其他 bean 定义。特别是,你可以通过 BeanDefinitionRegistryPostProcessor 来注册一些常规的BeanFactoryPostProcessor,因为此时所有常规的BeanFactoryPostProcessor 都还没开始被处理,BeanDefinitionRegistryPostProcessor 就已经开始先后执行postProcessBeanDefinitionRegistry和postProcessBeanFactory
同时BeanDefinitionRegistryPostProcessor 是BeanDefinitionRegistry的后置处理器,而BeanDefinitionRegistry是BeanFactory信息保存中心,BeanFactory加载bean的定义信息需要通过BeanDefinitionRegistry获取
现在我们定义两个后置处理器看看调用的前后效果
@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
System.out.println("MyBeanDefinitionRegistryPostProcessor:postProcessBeanDefinitionRegistry===============");
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("MyBeanDefinitionRegistryPostProcessor:postProcessBeanFactory===============");
}
}
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Autowired
private MySql mySql;
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("开始执行我们的BeanFactoryPostProcessor=============");
//此时的mySql没有被创建,调用beanFactory.getBean才会被创建
if (mySql==null){
System.out.println("BeanFactory现在只是保存了bean消息,没有创建对象");
}else {
System.out.println("BeanFactory现在即保存了bean消息,也创建了对象");
}
Object mySql2 = beanFactory.getBean("mySql");
if (mySql2==null){
System.out.println("调用beanFactory.getBean才会被创建后,BeanFactory现在只是保存了bean消息,没有创建对象");
}else {
BeanDefinition mysql = beanFactory.getBeanDefinition("mySql");
//为bean设置属性
MutablePropertyValues propertyValues = mysql.getPropertyValues();
propertyValues.add("name","我是后置处理器的mysql");
System.out.println("调用beanFactory.getBean才会被创建后,BeanFactory现在即保存了bean消息,也创建了对象");
}
}
}

结论是:可以看到BeanDefinitionRegistryPostProcessor比BeanFactoryPostProcessor调用要早,它们都是在spring容器还没有实例化bean前就调用了,但是spring容器已经将所有的bean的申明信息加载到了容器中,这个叫做spring的标准化加载,通过beanFactory.getBean方法就能进行实例化了。还要我们发现继承了Condition方法的类执行matches方法还要比这两个后置处理器要早,并且其调用时间也是在spring的标准化加载之前
Spring的监听器
ApplicationListener
ApplicationContext事件机制是观察者设计模式的实现,通过ApplicationEvent类和ApplicationListener接口,可以实现ApplicationContext事件处理。ApplicationListener里面只有一个onApplicationEvent方法。如果在ApplicationContext部署一个实现了ApplicationListener接口的bean,那么每当在一个ApplicationEvent发布到 ApplicationContext时,调用ApplicationContext.publishEvent()方法,这个bean得到通知。
我们自定义一个ApplicationListener看看它的调用时机
@Component
public class MyApplicationListener implements ApplicationListener<ApplicationEvent> {
@Override
public void onApplicationEvent(ApplicationEvent applicationEvent) {
System.out.println("事件开始:"+applicationEvent+"=================================");
}
}

结论:我们可以看到,ApplicationListener是默认是在spring容器初始化完成后和容器销毁后进行触发
我们可以自己发布事件去触发在ApplicationContext部署一个实现了ApplicationListener接口的bean,那么每当在一个ApplicationEvent发布到 ApplicationContext时,调用ApplicationContext.publishEvent()方法,这个bean得到通知
自定义发布事件
public class MyApplicationEven extends ApplicationEvent {
public MyApplicationEven(Object source) {
super(source);
if (source instanceof String)
System.out.println("开始触发事件:"+source);
}
}
发布一个事件
@org.junit.Test
public void test22(){
AnnotationConfigApplicationContext ac =
new AnnotationConfigApplicationContext(SpringConfig.class);
//发布自定义的事件
ac.publishEvent(new MyApplicationEven("我发布的事件"));
ac.close();
}

@Component
public class RefreshListener implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
ApplicationContext applicationContext = event.getApplicationContext();
if (applicationContext.getParent()==null) {
System.out.println("ContextRefreshedEvent容器刷新方法的监听器==========");
}
}
}
AOP
1、execution(* *(..)):表示匹配所有方法
2、execution(public * com. savage.service.UserService.*(..)):表示匹配com.savage.server.UserService中所有的公有方法
3、execution(* com.savage.server..*.*(..)):表示匹配com.savage.server包及其子包下的所有方法
@Aspect
public class AspectLogs {
@Pointcut("execution(public * com.example.springLearn.service.AopService.*(..))")
public void pointCut(){
}
@Before("pointCut()")
public void before(JoinPoint joinPoint){
System.out.println("Aop的前置方法-------------------------------");
System.out.println("目标方法名为:" + joinPoint.getSignature().getName());
System.out.println("目标方法所属类的简单类名:" +joinPoint.getSignature().getDeclaringType().getSimpleName());
System.out.println("目标方法所属类的类名:"+ joinPoint.getSignature().getDeclaringTypeName());
System.out.println("目标方法声明类型:"+ Modifier.toString(joinPoint.getSignature().getModifiers()));
//获取传入目标方法的参数
Object[] args = joinPoint.getArgs();
for (int i = 0; i < args.length; i++) {
System.out.println("第" + (i+1) + "个参数为:" + args[i]);
}
System.out.println("被代理的对象:" + joinPoint.getTarget());
System.out.println("代理对象自己:" + joinPoint.getThis());
}
@After("pointCut()")
public void after(){
System.out.println("Aop的后置方法-------------------------------");
}
@Around("pointCut()")
public void around(JoinPoint joinPoint) throws Throwable {
System.out.println("AOP的环绕方法...................");
System.out.println("开始增强方法的执行...................");
//增强方法的执行
((ProceedingJoinPoint) joinPoint).proceed();
System.out.println("增强方法执行结束-------------------------------");
}
@AfterReturning("pointCut()")
public void returnAop(){
System.out.println("Aop的正常返回方法-------------------------------");
}
@AfterThrowing("pointCut()")
public void exceptionAop(){
System.out.println("Aop的异常调用方法-------------------------------");
}
}
被代理对象
public class AopService {
public Integer testAop() {
Random random = new Random();
int i = random.nextInt(5000);
System.out.println(i);
return i;
}
}
@EnableAspectJAutoProxy
@Configuration
@Import({AopService.class, AspectLogs.class})
public class AopConfig {
@Test
public void test1(){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AopConfig.class);
AopService aopService = applicationContext.getBean(AopService.class);
aopService.testAop();
}
}

JDBC事务
如果应用程序中直接使用JDBC来进行持久化,DataSourceTransactionManager会为你处理事务边界。为了使用DataSourceTransactionManager,你需要使用如下的XML将其装配到应用程序的上下文定义中
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
在springboot中开启
@SpringBootApplication
@EnableTransactionManagement
public class LearnApplication {
public static void main(String[] args) {
SpringApplication.run(LearnApplication.class, args);
}
}
实际上,DataSourceTransactionManager是通过调用java.sql.Connection来管理事务,而后者是通过DataSource获取到的。通过调用连接的commit()方法来提交事务,同样,事务失败则通过调用rollback()方法进行回滚。
使用spring声明式事务,spring使用AOP来支持声明式事务,会根据事务属性,自动在方法调用之前决定是否开启一个事务,并在方法执行之后决定事务提交或回滚事务。
事务的传播行为:
PROPAGATION_REQUIRED:表示当前方法必须运行在事务中。如果当前事务存在,方法将会在该事务中运行。否则,会启动一个新的事务(默认)
PROPAGATION_SUPPORTS:表示当前方法不需要事务上下文,但是如果存在当前事务的话,那么该方法会在这个事务中运行
PROPAGATION_MANDATORY:表示该方法必须在事务中运行,如果当前事务不存在,则会抛出一个异常
PROPAGATION_REQUIRED_NEW:表示当前方法必须运行在它自己的事务中。一个新的事务将被启动。如果存在当前事务,在该方法执行期间,当前事务会被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManager
PROPAGATION_NOT_SUPPORTED:表示该方法不应该运行在事务中。如果存在当前事务,在该方法运行期间,当前事务将被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManager
PROPAGATION_NEVER:表示当前方法不应该运行在事务上下文中。如果当前正有一个事务在运行,则会抛出异常
PROPAGATION_NESTED:表示如果当前已经存在一个事务,那么该方法将会在嵌套事务中运行。嵌套的事务可以独立于当前事务进行单独地提交或回滚。如果当前事务不存在,那么其行为与PROPAGATION_REQUIRED一样。注意各厂商对这种传播行为的支持是有所差异的。可以参考资源管理器的文档来确认它们是否支持嵌套事务
我们分析默认的PROPAGATION_REQUIRED,也是最常用的
例如:
@Transactional
methodA{
……
methodB();
……
}
@Transactional
methodB{
……
}
单独调用methodB方法:Spring保证在methodB方法中所有的调用都获得到一个相同的连接。在调用methodB时,没有一个存在的事务,所以获得一个新的连接,开启了一个新的事务。
main{
metodB();
}
相当于
Main{
Connection con=null;
try{
con = getConnection();
con.setAutoCommit(false);
//方法调用
methodB();
//提交事务
con.commit();
} Catch(RuntimeException ex) {
//回滚事务
con.rollback();
} finally {
//释放资源
closeCon();
}
}
调用methodA:调用MethodA时,环境中没有事务,所以开启一个新的事务.当在MethodA中调用MethodB时,环境中已经有了一个事务,所以methodB就加入当前事务。
main{
metodA();
}
相当于:
main{
Connection con = null;
try{
con = getConnection();
methodA();
con.commit();
} catch(RuntimeException ex) {
con.rollback();
} finally {
closeCon();
}
}
参考:https://blog.csdn.net/mocas_wang/article/details/109012583
事务不生效的场景:https://blog.csdn.net/f641385712/article/details/80445933
网友评论