【Spring总结】

Sping的发展

1.核心功能增强:Spring框架的核心一直是IoC(Inversion of Control,控制反转)和AOP(Aspect-Oriented Programming,面向切面编程)等功能。随着时间的推移,Spring框架不断增强这些核心功能,并添加了新的特性和模块,以满足不断变化的开发需求。
2.模块化:Spring框架被分解为多个模块,每个模块都专注于不同的功能,例如Spring Core、Spring MVC、Spring Data、Spring Security等。这种模块化的设计使得开发人员可以根据需要选择性地使用框架的不同部分,从而提高了灵活性和可维护性。
3.整合其他技术:Spring框架通过提供与其他流行技术的整合,使得开发人员可以更轻松地集成不同的技术栈。例如,Spring Boot为开发人员提供了快速启动和配置Spring应用程序的能力,Spring Cloud用于构建基于微服务架构的应用程序,Spring Data用于简化与数据访问相关的操作等。

响应式编程支持:随着互联网应用程序对响应时间和吞吐量的要求不断增加,Spring框架引入了对响应式编程的支持。Spring 5引入了对Reactive Streams API的支持,并提供了用于构建反应式应用程序的Spring WebFlux模块。

社区和生态系统的发展:Spring框架拥有一个庞大而活跃的社区,这个社区不断提供新的想法、贡献代码,并提供帮助和支持。Spring生态系统中有许多与Spring框架兼容的第三方库和工具,为开发人员提供了丰富的选择和支持。
spring的架构图:
在这里插入图片描述
Spring 主要包含了:spring-web、spring-core、spring-context、spring-aop、spring-jdbc、Spring-test、spring-security
Spring框架包含了许多模块,每个模块都专注于不同的功能。以下是Spring框架中一些主要的核心模块:
1、Spring Core Container模块:Spring核心容器模块提供了IoC(Inversion of Control,控制反转)和DI(Dependency Injection,依赖注入)的功能。它包括了Spring的基本功能,如Bean管理、依赖注入、生命周期管理等。
2、Spring AOP模块:Spring的AOP(Aspect-Oriented Programming,面向切面编程)模块提供了面向切面编程的支持。通过AOP,开发人员可以将横切关注点(cross-cutting concerns)从应用程序的核心逻辑中分离出来,实现更好的模块化和可维护性。
3、Spring JDBC模块:Spring的JDBC模块简化了与数据库的交互。它提供了模板类和回调机制,以及声明式事务管理的功能,使得数据库访问更加简单和可靠。
4、Spring ORM模块:Spring的ORM(Object-Relational Mapping,对象-关系映射)模块集成了不同的ORM框架,如Hibernate、JPA等。它简化了对象与数据库之间的映射关系,提供了对象持久化的支持。
5、Spring Web模块:Spring的Web模块包括了Spring MVC框架,用于构建基于MVC(Model-View-Controller,模型-视图-控制器)模式的Web应用程序。它提供了处理HTTP请求、管理会话状态、渲染视图等功能。
6、Spring Security模块:Spring Security模块用于提供认证和授权的安全功能。它可以集成到Spring应用程序中,提供诸如用户身份验证、权限管理、加密解密等安全特性。
7、Spring Test模块:Spring Test模块包括了用于编写单元测试和集成测试的支持类和工具。它提供了对Spring应用程序的各个层次进行测试的能力,包括对控制器、服务层、数据访问层等的测试支持。

spring的注解:

在这里插入图片描述

Web:

@Controller:组合注解(组合了@Component注解),应用在MVC层(控制层)。
@RestController:该注解为一个组合注解,相当于@Controller和@ResponseBody的组合,注解在类上,意味着,该Controller的所有方法都默认加上了@ResponseBody。
@RequestMapping:用于映射Web请求,包括访问路径和参数。如果是Restful风格接口,还可以根据请求类型使用不同的注解:
@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@ResponseBody:支持将返回值放在response内,而不是一个页面,通常用户返回json数据。
@RequestBody:允许request的参数在request体中,而不是在直接连接在地址后面。
@PathVariable:用于接收路径参数,比如@RequestMapping(“/hello/{name}”)申明的路径,将注解放在参数中前,即可获取该值,通常作为Restful的接口实现方法。
@RestController:该注解为一个组合注解,相当于@Controller和@ResponseBody的组合,注解在类上,意味着,该Controller的所有方法都默认加上了@ResponseBody。

容器:

@Component:表示一个带注释的类是一个“组件”,成为Spring管理的Bean。当使用基于注解的配置和类路径扫描时,这些类被视为自动检测的候选对象。同时@Component还是一个元注解。
@Service:组合注解(组合了@Component注解),应用在service层(业务逻辑层)。
@Repository:组合注解(组合了@Component注解),应用在dao层(数据访问层)。
@Autowired:Spring提供的工具(由Spring的依赖注入工具(BeanPostProcessor、BeanFactoryPostProcessor)自动注入)。
@Qualifier:该注解通常跟 @Autowired 一起使用,当想对注入的过程做更多的控制,@Qualifier 可帮助配置,比如两个以上相同类型的 Bean 时 Spring 无法抉择,用到此注解
@Configuration:声明当前类是一个配置类(相当于一个Spring配置的xml文件)
@Value:可用在字段,构造器参数跟方法参数,指定一个默认值,支持 #{} 跟 ${} 两个方式。一般将 SpringbBoot 中的 application.properties 配置的属性值赋值给变量。
@Bean:注解在方法上,声明当前方法的返回值为一个Bean。返回的Bean对应的类中可以定义init()方法和destroy()方法,然后在@Bean(initMethod=”init”,destroyMethod=”destroy”)定义,在构造之后执行init,在销毁之前执行destroy。
@Scope:定义我们采用什么模式去创建Bean(方法上,得有@Bean) 其设置类型包括:Singleton 、Prototype、Request 、 Session、GlobalSession。

AOP:

@Aspect:声明一个切面(类上) 使用@After、@Before、@Around定义建言(advice),可直接将拦截规则(切点)作为参数。
@After :在方法执行之后执行(方法上)。
@Before: 在方法执行之前执行(方法上)。
@Around: 在方法执行之前与之后执行(方法上)。
@PointCut: 声明切点 在java配置类中使用@EnableAspectJAutoProxy注解开启Spring对AspectJ代理的支持(类上)。

事务:

@Transactional:在要开启事务的方法上使用@Transactional注解,即可声明式开启事务。

spring的设计模式的应用

1、工厂模式(Factory Pattern):Spring中广泛使用工厂模式来管理对象的创建。例如,ApplicationContext充当了一个工厂,负责创建和管理应用程序中的bean。
2、单例模式(Singleton Pattern):Spring的默认作用域是单例,这意味着Spring容器中的bean默认情况下只会创建一个实例,并在整个应用程序中共享。
3、代理模式(Proxy Pattern):Spring AOP(Aspect-Oriented Programming)模块使用代理模式来实现切面。Spring通过动态代理或CGLIB代理来创建切面,并将切面织入到目标对象的方法中。
4、观察者模式(Observer Pattern):Spring的事件机制使用了观察者模式。ApplicationContext发布事件,而事件监听器则订阅并响应这些事件。
5、模板模式(Template Pattern):Spring JDBC和Spring的ORM(如HibernateTemplate)使用了模板模式。Spring提供了模板类(如JdbcTemplate)来封装常见的操作,开发人员只需关注业务逻辑即可,数据库连接和资源管理由模板类来处理。
6、适配器模式(Adapter Pattern):Spring MVC框架使用了适配器模式来处理客户端请求。DispatcherServlet作为一个前端控制器(Front Controller),使用不同的HandlerAdapter来适配不同类型的处理器(Controllers)。
7、策略模式(Strategy Pattern):Spring Security框架中的许多安全策略采用了策略模式的实现方式。开发人员可以根据需求选择和配置不同的安全策略。
8、建造者模式(Builder Pattern):Spring Boot中的Starter和自动配置机制使用了建造者模式。Starter提供了一种便捷的方式来配置应用程序所需的依赖项,而自动配置机制则根据环境和类路径上的依赖项来自动构建和配置Spring应用程序。

Spring Bean的生命周期

bean的生命周期流程图:
在这里插入图片描述
简单说就是四个流程:
1.实例化:第 1 步,实例化一个 Bean 对象
2.属性赋值:第 2 步,为 Bean 设置相关属性和依赖
3.初始化:初始化的阶段的步骤比较多,5、6步是真正的初始化,第 3、4 步为在初始化前执行,第 7 步在初始化后执行,初始化完成之后,Bean就可以被使用了
4.销毁:第 8~10步,第8步其实也可以算到销毁阶段,但不是真正意义上的销毁,而是先在使用前注册了销毁的相关调用接口,为了后面第9、10步真正销毁 Bean 时再执行相应的方法。
初始化简单讲就是定义一个Bean类,实现DisposableBean,InitializingBean, BeanFactoryAware, BeanNameAware这4个接口,同时还有自定义的init-method和destroy-method,继承了这些类和接口里的方法,来实现某些特定的功能。

public class UserBean implements BeanNameAware, BeanFactoryAware, InitializingBean , DisposableBean {
    @Override
    public void setBeanName(String name) {
        System.out.println("设置bean名称");
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("设置bean工厂");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("设置完书属性之后,要做什么操作");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("销毁方法");
    }
    public void init(){
        System.out.println("初始化方法");
    }
}

初始化之前和初始化之后,bean需要实现某些业务的方法:

public class MyBeanPostPocessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("初始化之前,对bean的操作");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("初始化之后,对bean的操作");
        return bean;
    }
}

配置文件指定初始化方法

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean name="myBeanPostProcessor" class="com.test.MyBeanPostProcessor" />
    <bean name="UserBean" class="com.test.UserBean"
          init-method="init" destroy-method="destroyMethod">
    </bean>

</beans>

Spring的源码解析:

spring的核心入口类:ClassPathXmlApplicationContext,看spring源码的入口

        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("test.xml");

ClassPathXmlApplicationContext继承的抽象类或者接口图:
在这里插入图片描述
也可以自己实现ClassPathXmlApplicationContext类,按照自己的想法,去实现特定的方法:

public class MyClassPathXmlApplicationContext extends ClassPathXmlApplicationContext {


    public MyClassPathXmlApplicationContext(String... configLocations){
        super(configLocations);
    }

    @Override
    protected void initPropertySources() {
        System.out.println("扩展initPropertySource");
        getEnvironment().setRequiredProperties("username");
    }

    @Override
    protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
//        super.setAllowBeanDefinitionOverriding(false);
//        super.setAllowCircularReferences(false);
        super.addBeanFactoryPostProcessor(new MyBeanFactoryPostProcessor());
        super.customizeBeanFactory(beanFactory);
    }

    @Override
    protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        System.out.println("扩展实现postProcessBeanFactory方法");
    }
}

进入ClassPathXmlApplication中找到核心方法refresh:

public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			/**
			 * 前戏,做容器刷新前的准备工作
			 * 1、设置容器的启动时间
			 * 2、设置活跃状态为true
			 * 3、设置关闭状态为false
			 * 4、获取Environment对象,并加载当前系统的属性值到Environment对象中
			 * 5、准备监听器和事件的集合对象,默认为空的集合
			 */

			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			// 创建容器对象:DefaultListableBeanFactory
			// 加载xml配置文件的属性值到当前工厂中,最重要的就是BeanDefinition
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			// beanFactory的准备工作,对各种属性进行填充
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				// 子类覆盖方法做额外的处理,此处我们自己一般不做任何扩展工作,但是可以查看web中的代码,是有具体实现的
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				// 调用各种beanFactory处理器
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				// 注册bean处理器,这里只是注册功能,真正调用的是getBean方法
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				// 为上下文初始化message源,即不同语言的消息体,国际化处理
				initMessageSource();

				// Initialize event multicaster for this context.
				// 初始化事件监听多路广播器
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				// 留给子类来初始化其他的bean
				onRefresh();

				// Check for listener beans and register them.
				// 在所有注册的bean中查找listener bean,注册到消息广播器中
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				// 初始化剩下的单实例(非懒加载的)
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				// 完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人
				finishRefresh();
			}

我们进入到finishBeanFactoryInitialization(beanFactory方法:

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
		// Initialize conversion service for this context.
		// 为上下文初始化类型转换器
		if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
				beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
			beanFactory.setConversionService(
					beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
		}

		// Register a default embedded value resolver if no bean post-processor
		// (such as a PropertyPlaceholderConfigurer bean) registered any before:
		// at this point, primarily for resolution in annotation attribute values.
		// 如果beanFactory之前没有注册嵌入值解析器,则注册默认的嵌入值解析器,主要用于注解属性值的解析
		if (!beanFactory.hasEmbeddedValueResolver()) {
			beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
		}

		// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
		// 尽早初始化loadTimeWeaverAware bean,以便尽早注册它们的转换器
		String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
		for (String weaverAwareName : weaverAwareNames) {
			getBean(weaverAwareName);
		}

		// Stop using the temporary ClassLoader for type matching.
		// 禁止使用临时类加载器进行类型匹配
		beanFactory.setTempClassLoader(null);

		// Allow for caching all bean definition metadata, not expecting further changes.
		// 冻结所有的bean定义,说明注册的bean定义将不被修改或任何进一步的处理
		beanFactory.freezeConfiguration();

		// Instantiate all remaining (non-lazy-init) singletons.
		// 实例化剩下的单例对象
		beanFactory.preInstantiateSingletons();
	}

进入到preInstantiateSingletons()方法:

public void preInstantiateSingletons() throws BeansException {
		if (logger.isTraceEnabled()) {
			logger.trace("Pre-instantiating singletons in " + this);
		}

		// Iterate over a copy to allow for init methods which in turn register new bean definitions.
		// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
		// 将所有BeanDefinition的名字创建一个集合
		List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

		// Trigger initialization of all non-lazy singleton beans...
		// 触发所有非延迟加载单例bean的初始化,遍历集合的对象
		for (String beanName : beanNames) {
			// 合并父类BeanDefinition
 			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
			// 条件判断,抽象,单例,非懒加载
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
				// 判断是否实现了FactoryBean接口
				if (isFactoryBean(beanName)) {
					// 根据&+beanName来获取具体的对象
					Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
					// 进行类型转换
					if (bean instanceof FactoryBean) {
						FactoryBean<?> factory = (FactoryBean<?>) bean;
						// 判断这个FactoryBean是否希望立即初始化
						boolean isEagerInit;
						if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
							isEagerInit = AccessController.doPrivileged(
									(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
									getAccessControlContext());
						}
						else {
							isEagerInit = (factory instanceof SmartFactoryBean &&
									((SmartFactoryBean<?>) factory).isEagerInit());
						}
						//  如果希望急切的初始化,则通过beanName获取bean实例
						if (isEagerInit) {
							getBean(beanName);
						}
					}
				}
				else {
					// 如果beanName对应的bean不是FactoryBean,只是普通的bean,通过beanName获取bean实例
					getBean(beanName);
				}
			}
		}

		// Trigger post-initialization callback for all applicable beans...
		// 遍历beanNames,触发所有SmartInitializingSingleton的后初始化回调
		for (String beanName : beanNames) {
			// 获取beanName对应的bean实例
			Object singletonInstance = getSingleton(beanName);
			// 判断singletonInstance是否实现了SmartInitializingSingleton接口
			if (singletonInstance instanceof SmartInitializingSingleton) {
				// 类型转换
				SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
				// 触发SmartInitializingSingleton实现类的afterSingletonsInstantiated方法
				if (System.getSecurityManager() != null) {
					AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
						smartSingleton.afterSingletonsInstantiated();
						return null;
					}, getAccessControlContext());
				}
				else {
					smartSingleton.afterSingletonsInstantiated();
				}
			}
		}
	}

这个方法的类ConfigurableListableBeanFactory.class
在这里插入图片描述
ConfigurableListableBeanFactory 和 ApplicationContext 都是Spring容器的接口,它们有各自的使用场景和功能:
ConfigurableListableBeanFactory 的使用场景:
1.Bean定义和注册:ConfigurableListableBeanFactory 可用于创建和注册Bean的定义,通常在编程式配置Spring容器时使用。这对于需要动态创建和注册Bean定义的情况很有用。
2.Bean的延迟初始化:您可以使用 ConfigurableListableBeanFactory 来设置Bean的延迟初始化属性,使容器只在需要时创建Bean实例。
3.Bean后处理器:如果您需要自定义Bean后处理器,可以使用 ConfigurableListableBeanFactory 来注册这些处理器,以对Bean实例进行定制化的初始化或销毁操作。
4.基本的Bean检索:虽然 ConfigurableListableBeanFactory 也允许您检索Bean实例,但它通常用于基本的编程式Bean检索,例如通过Bean名称检索。
ApplicationContext 的使用场景:
1.应用程序上下文管理:ApplicationContext 是Spring应用程序的主要上下文管理器。它通常用于加载和管理应用程序的配置,包括Bean定义、配置文件、资源、国际化等。
2.依赖注入:ApplicationContext 是依赖注入的核心容器,它负责创建、配置和管理Bean实例,并确保它们的依赖关系被满足。
3.AOP和事务管理:ApplicationContext 提供了AOP和事务管理的支持,您可以配置切面、通知和事务策略。
4.国际化和消息源:ApplicationContext 提供了国际化和消息资源管理的功能,使应用程序能够支持多语言和本地化。
事件发布:ApplicationContext 支持应用程序内部事件的发布和监听,这对于实现松耦合的组件通信非常有用。
5.Web应用程序上下文:Spring的 WebApplicationContext 扩展了 ApplicationContext,提供了在Web应用程序中的特定功能,如Servlet上下文和Web事件处理。
总的来说,ConfigurableListableBeanFactory 主要用于编程式配置和基本的Bean定义、检索以及自定义 Bean处理。ApplicationContext 是一个更高级的容器,适用于应用程序上下文管理、依赖注入、AOP、事务、国际化、事件发布等高级功能,特别适合开发应用程序。在大多数情况下,应用程序中使用的容器通常是 ApplicationContext 或其派生类型。

区别:
getBean 方法在 ConfigurableListableBeanFactory 和 ApplicationContext 接口中都存在,但它们之间有一些重要的区别,主要涉及到 Spring 容器的层次结构和功能。
ConfigurableListableBeanFactory:
1.ConfigurableListableBeanFactory 是Spring容器中Bean工厂的接口,它提供了访问和操作 Bean 定义和实例的基本方法。
getBean 方法允许从容器中获取指定名称的 Bean 实例,但通常需要传递类型参数用于类型安全检查。这意味着它返回的是原始 Bean 实例,你需要自行转型为具体的对象。
3.ConfigurableListableBeanFactory 不提供高级功能,如国际化、事件发布、AOP等,因为它的主要职责是管理Bean的定义和创建。
ApplicationContext:
1.ApplicationContext 是Spring容器的更高级别接口,它扩展了 ConfigurableListableBeanFactory 并添加了更多功能。
getBean 方法在 ApplicationContext 中除了允许获取Bean实例外,还允许传递Bean类型和其他可选参数来更精确地检索Bean。它返回的是Bean对象,无需手动进行类型转换。
2.ApplicationContext 提供了更多的功能,如国际化、事件发布、资源访问、AOP代理等。它还支持扩展,允许通过自定义的Bean后处理器等方式干预容器的行为。
总的来说,ConfigurableListableBeanFactory 是一个较低级别的 Bean 工厂接口,主要用于 Bean 的创建和管理。3.ApplicationContext 则是更高级别的接口,它构建在 ConfigurableListableBeanFactory 之上,并提供了更多功能和便捷性,通常更适合应用程序的上下文管理。

spring事务

Spring 事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,Spring 是无法提供事务功能的。Spring 只提供统一事务管理接口,具体实现都是由各数据库自己实现,数据库事务的提交和回滚是通过数据库自己的事务机制实现。

spring事务的传播行为

REQUIRED 默认值。如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
REQUIRES_NEW 创建一个新的事务,如果当前存在事务,则把当前事务挂起。
SUPPORTS 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
NOT_SUPPORTED 以非事务方式运行,如果当前存在事务,则把当前事务挂起。
NEVER 以非事务方式运行,如果当前存在事务,则抛出异常。
MANDATORY 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
NESTED 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于 REQUIRED。

spring事务的隔离级别

事务的隔离界别,默认五个级别:
默认级别 默认值,表示使用底层数据库的默认隔离级别,对大部分数据库而言,通常这个值就是读未提交。
读未提交 表示一个事务可以读取另一个事务已经提交的数据,该级别不可以防止脏读,幻读,和不可重复读。
读已提交 表示一个事务只能读取另一个事务已经提交的数据,该级别可以防止脏读,这也是大多数情况的推荐值。
可重复读 表示一个事务在整个过程中,可以多次重复执行某个查询,并且每次返回的记录都相同。
可序列化 所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

sping事务使用的注意点:

1、不要在接口上声明@Transactional,而要在具体类的方法上使用 @Transactional 注解,否则注解可能无效。

2、不要图省事,将@Transactional放置在类级的声明中,放在类声明,会使得所有方法都有事务。故@Transactional应该放在方法级别,不需要使用事务的方法,就不要放置事务,比如查询方法。否则对性能是有影响的。

3、@Transactional 的事务开启 ,或者是基于接口的 或者是基于类的代理被创建。所以在同一个类中一个方法调用另一个方法有事务的方法,事务是不会起作用的 。

4、用REQUIRES_NEW的时候,发现没有起作用
分析了一下,原因是A方法(有事务)调用B方法(要独立新事务),如果两个方法写在同一个类里,spring的事务会只处理能同一个。
解决方案1:需要将两个方法分别写在不同的类里。
解决方案2:方法写在同一个类里,但调用B方法的时候,将service自己注入自己,用这个注入对象来调用B方法。
5、使用了@Transactional的方法,只能是public,@Transactional注解的方法都是被外部其他类调用才有效,故只能是public。道理和上面的有关联。故在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,它也不会报错,但事务无效。
6、默认只有RuntimeExcetion会触发回滚,经验证明确实如此,所以rollbackFor可以自行设置如下:rollbackFor = {Exception.class},当然具体业务具体处理,可能有的业务抛出的某些异常并不需要触发回滚,所以此时应该细化处理异常。

@Transactional(propagation = Propagation.REQUIRES_NEW,rollbackFor={/自定义Exception,可以是多个/ IOException.class})
上面的这个rollbackFor配置,可以理解为:当配置这个事务的方法内返回了IOException,则会触发回滚操作。

7、MySQL数据库表引擎应为InnoDB,否则不支持事务。

spring事失效的场景

1、 查看数据库中使用的表是否都是 InnoDB 的引擎,有些表为了追求写入的性能,比如记录日志的表,会将引擎改为 MyiSAM,如果数据库引擎不支持,那么添加的事务也就不会生效。

2、 事务要加在 public 方法上,否则事务将不会起作用,如果要用在非 public 方法上,事务不会生效。如果方法被 final 修饰, spring 事务底层使用了 aop, 也就是通过jdk动态代理或者cglib,生成了代理类,而被final 或者 staitc的方法,是不能重写或者代理,因此事务就不会生效。

3、 在事务内部调用本类的另一个事务方法,那么被调用的一方事务不会生效。因为spring 的事务是使用动态代理生效的,本类内部的调用相当于是this.method 的调用,没有经过spring代理所以事务不会生效。如果非要在类内部进行调用,需要按照如下图操作,updateUserInfo 调用方法 modifyUserInfo,需要使用 AopContext获取当前对象进行调用执行。同时还要设置 proxyTargetClass= true,改值默认为 false。
4、 注意事务设置的隔离级别,如果项目中配置了多个数据源,就会有多个事务管理器,在执行事务的时候需要指定其事务管理器。事务的传播属性和隔离级别是默认的,超时时间默认是 -1,不设置超时时间。异常回滚和异常不回滚需要根据业务的情况进行设置。
5、 方法内部不能将异常 try-catch ,如果方法内部都把异常给处理了,那么事务捕捉不到异常信息,事务自然不会回滚,也就不会生效。方法内部把异常信息给处理了,就不能被事务Aop 拦截进行处理,自然就会进行回滚操作。

6、 建议事务 @Transactional 注解需要在具体的实现类上进行标注,而不是在接口层标注。注解是不能继承的,所以只有在基于接口的代理(PROXY)时事务才生效。如果正在使用基于类(AspectJ)代理时,那么注解不会被基于类的代理识别,对象也不会被事务代理所包装,因此事务是不能生效的。

7、 多线程调用,在项目开发过程中多线程的应用场景是很多的,在多线程的场景下,主线程所在的 Context 和多线程执行下的方法不在同一个上下文,我们知道 spring 的事务是通过数据库连接来实现的,数据库连接是存放在一个 ThreadLocal 中的,只有在同一个线程上下文下,事务的操作才能生效。

8、在事务方法中加锁,可能会导致锁失效

无论是Java自带的锁,还是分布式锁,都有可能出现没锁住的情况

原因是解锁先于事务提交,一旦锁释放后其它线程就可以获取到锁了,由于事务还没提交,所以新线程读到的还是旧数据(跟前一个线程读取到的数据是一样的),这就相当于多个线程做了一模一样的事情了。

spring常见问题:

Spring怎么解决循环依赖的呢。

spring解决循环依赖主要依靠三级缓存。
一级缓存 : Map<String,Object> singletonObjects,单例池,用于保存实例化、属性赋值(注入)、初始化完成的 bean 实例
二级缓存 : Map<String,Object> earlySingletonObjects,早期曝光对象,用于保存实例化完成的 bean 实例
三级缓存 : Map<String,ObjectFactory<?>> singletonFactories,早期曝光对象工厂,用于保存 bean 创建工厂,以便于后面扩展有机会创建代理对象。

为什么使用三级缓存,为什么不使用三级缓存

不行,主要是为了⽣成代理对象。如果是没有代理的情况下,使用二级缓存解决循环依赖也是OK的。但是如果存在代理,三级没有问题,二级就不行了。

因为三级缓存中放的是⽣成具体对象的匿名内部类,获取Object的时候,它可以⽣成代理对象,也可以返回普通对象。使⽤三级缓存主要是为了保证不管什么时候使⽤的都是⼀个对象。

假设只有⼆级缓存的情况,往⼆级缓存中放的显示⼀个普通的Bean对象,Bean初始化过程中,通过 BeanPostProcessor 去⽣成代理对象之后,覆盖掉⼆级缓存中的普通Bean对象,那么可能就导致取到的Bean对象不一致了。

  • 9
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值