Spring5
前置知识
什么是 Spring
Spring 框架是 Java 应用最广的框架,它的成功来源于理念,而不是技术本身,它的理念包括 IoC (Inversion of Control,控制反转) 和 AOP(Aspect Oriented Programming,面向切面编程)。理念:每个bean与bean之间的关系统一交给 Spring IoC 容器管理。
Spring体系结构
-
Spring Core:主要组件是BeanFactory,创建JavaBean的工厂,使用控制反转(IOC) 模式 将应用程序的配置和依赖性规范与实际的应用程序代码分开。
-
Spring AOP:集成了面向切面的编程功能(AOP把一个业务流程分成几部分,例如权限检查、业务处理、日志记录,每个部分单独处理,然后把它们组装成完整的业务流程。每个部分被称为切面),可以将声明性事物管理集成到应用程序中。
-
Spring Cntext:一个核心配置文件,为Spring框架提供上下文信息。
-
Spring Do:Spring操作数据库的模块。
-
Spring ORM:Spring集成了各种orm(object relationship mapping 对象关系映射)框架的模块,集成mybatis
-
Spring Web集成各种优秀的web层框架的模块(Struts、Springmvc)
-
Spring web MVC:Spring web层框架
思考一个问题 为什么启动SpringBoot项目的时候需要加上Configuration、@ComponentScan
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
看一下 @SpringBootApplication 注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
看一下 @SpringBootConfiguration 注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
@SpringBootApplication 包含 @ComponentScan 和 @SpringBootConfiguration。@SpringBootConfiguration 包含 @Configuration。
@Configuration 是为了注册bean,@CompnentScan 是为了扫描要注册的bean。
快速构建Spring环境
Maven依赖信息
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.0.RELEASE</version>
</dependency>
xml方式环境搭建
配置文件:src\main\resources\applicationContext.xml
<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
">
<!-- 容器id class 使用java的反射机制初始化 -->
<bean id="userEntity" class="com.pjw.entity.UserEntity">
<!-- 使用set方法进行注入 -->
<property name="userId" value="10"/>
<property name="userName" value="pjw"/>
</bean>
</beans>
UserEntity.java
public class UserEntity {
private Integer userId;
private String userName;
public void setUserId(Integer userId) {
this.userId = userId;
}
public void setUserName(String userName) {
this.userName = userName;
}
@Override
public String toString() {
return "UserEntity{" +
"userId=" + userId +
", userName='" + userName + '\'' +
'}';
}
}
Main.java
public class Main {
public static void main(String[] args) {
// 1.读取spring配置文件,创建IOC容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 2.从SpringIoc容器获取userEntity
UserEntity userEntity = (UserEntity) applicationContext.getBean("userEntity");
System.out.println(userEntity);
}
}
Spring 中注入的 bean id 重复的话会怎么样
IoC 容器启动的时候会报错
注解方式环境搭建
UserEntity.java
public class UserEntity {
private Integer userId;
private String userName;
public UserEntity(Integer userId, String userName) {
this.userId = userId;
this.userName = userName;
}
@Override
public String toString() {
return "UserEntity{" +
"userId=" + userId +
", userName='" + userName + '\'' +
'}';
}
}
MySpringConfig.java MySpringConfig 这个类也会被注册成为 bean
// @Configuration 等同于配置的spring配置文件
@Configuration
public class MySpringConfig {
// bean id 为方法名称
@Bean
public UserEntity userEntity() {
return new UserEntity(10, "pjw");
}
}
Main.java
public class Main {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MySpringConfig.class);
UserEntity userEntity = applicationContext.getBean("userEntity", UserEntity.class);
System.out.println(userEntity);
}
}
@ComponentScan用法
bean id默认为小写开头的类名,可以在@Component注解里指定 bean id
- @ComponentScan 会把指定包路径上包含 @Component 注解的类注册成 bean
@Configuration
@ComponentScan("com.pjw")
public class MySpringConfig { }
- 指定包路径上包含指定注解的类注册成 bean
@Configuration
@ComponentScan(value = "com.pjw", includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class)}, useDefaultFilters = false)
public class MySpringConfig {
@Bean
public UserEntity userEntity() {
return new UserEntity(10, "pjw");
}
}
- 指定包路径上排除指定注解,包含 @Component 注解的类注册成 bean
@Configuration
@ComponentScan(value = "com.pjw", excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class)}, useDefaultFilters = true)
public class MySpringConfig {
@Bean
public UserEntity userEntity() {
return new UserEntity(10, "pjw");
}
}
FilterType 有五种类型
-
ANNOTATION:注解类型
-
ASSIGNABLE_TYPE:ANNOTATION:指定的类型
-
ASPECTJ:按照Aspectj的表达式,基本上不会用到
-
REGEX:按照正则表达式
-
CUSTOM:自定义规则
获取所有 IoC 容器中的 bean
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
bean 的作用域
Spring 中 bean 默认是单例
可以使用 @Scope 来设置 bean 的作用域
| @Scope 值 | 描述 |
|---|---|
| singleton | 全局有且仅有一个实例。 |
| prototype | 每次获取Bean的时候都会有一个新的实例。 |
| request | 针对每次请求都会产生一个新的Bean对象,并且该Bean对象仅在当前Http请求内有效。 |
| session | 针对每次请求都会产生一个新的Bean对象,并且该Bean仅在当前Http session内有效。 |
bean 是什么时候创建的
单例的时候默认是在容器初始化的时候创建的。
可以使用 @Lazy 注解来设置什么时候创建。@Lazy 注解值为 true 的时候是第一次获取的时候创建,false 的话容器初始化的时候创建。
@Lazy 默认值为 true。
多例是每次获取的时候创建的。
bean 的初始化指的是对象已经创建并且里面的所有 set 方法都已经执行完毕了。
销毁 bean
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MySpringConfig.class);
// 把 bean 的 map 集合清空
applicationContext.close();
}
}
bean 初始化完成之后、销毁之后执行的方法
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserEntity {
private Integer userId;
private String userName;
private void myInitMethod() {
System.out.println("myInitMethod");
}
private void myDestroyMethod() {
System.out.println("myDestroyMethod");
}
}
@Configuration
public class MySpringConfig {
@Bean(initMethod = "myInitMethod",destroyMethod = "myDestroyMethod")
public UserEntity userEntity(){
return new UserEntity(19,"pjw");
}
}
或者
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserEntity implements InitializingBean, DisposableBean {
private Integer userId;
private String userName;
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("初始化完成");
}
@Override
public void destroy() throws Exception {
System.out.println("销毁完成");
}
}
@Configuration
public class MySpringConfig {
@Bean
public UserEntity userEntity(){
return new UserEntity(19,"pjw");
}
}
或者
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserEntity {
private Integer userId;
private String userName;
@PostConstruct
public void chushihuawancheng() throws Exception {
System.out.println("初始化完成");
}
@PreDestroy
public void xiaohuiwancheng() throws Exception {
System.out.println("销毁完成");
}
}
@Configuration
public class MySpringConfig {
@Bean
public UserEntity userEntity(){
return new UserEntity(19,"pjw");
}
}
通过 ApplicationContextAware 获取 ApplicationContext
@Component
public class MyApplication implements ApplicationContextAware {
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
UserEntity userEntity = (UserEntity)applicationContext.getBean("userEntity");
System.out.println(userEntity);
}
}
生命周期中 aware 依赖
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserEntity implements BeanNameAware, BeanFactoryAware, BeanClassLoaderAware {
private Integer userId;
private String userName;
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
System.out.println(classLoader);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println(beanFactory);
}
@Override
public void setBeanName(String name) {
System.out.println(name);
}
}
BeanPostProcessor 接口
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
// 每个 bean 执行自定义 init 方法之前处理
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println(bean);
System.out.println(beanName);
return null;
}
// 每个 bean 执行自定义 init 方法之后处理
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println(bean);
System.out.println(beanName);
retur
n null;
}
}
@Condition 根据条件判断注册 bean
public class MyCondition implements Condition{
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
// 获取当前环境配置
Environment environment = conditionContext.getEnvironment();
String osName = environment.getProperty("os.name");
if (osName.equals("Windows 7")) {
// 返回true 就是能够创建该bean
return false;
}
return false;
}
}
@Configuration
public class MySpringConfig {
@Bean
@Conditional(MyCondition.class)
public UserEntity userEntity() {
return new UserEntity(10, "pjw");
}
}
基于 @Import 注解注册 bean
bean id 为类的全路径名称
@Bean和@Import都是引入外部的Jar包
@Configuration
@Import(UserEntity.class)
public class MySpringConfig {
}
@EnableXXX 功能性注解实现原理
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({PayEntity.class, MyPayEntity.class})
public @interface EnablePayEntity {
// 只要启动的时候 加入该EnablePayEntity 就会将PayEntity,MyPayEntity实体类注入到spring ioc容器
// Enable注解的话 底层 实际上在调用 @Import({PayEntity.class, MyPayEntity.class})
}
@Configuration
@EnablePayEntity
public class MyConfig {
}
基于 ImportSelector 接口注册 bean
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
return new String[]{"com.pjw.MemberEntity", "com.pjw.MsEntity"};
}
}
@Configuration
@Import(MyImportSelector.class)
public class MyConfig {
}
基于 ImportBeanDefinitionRegistrar 接口注册 bean
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
// 手动注册到ioc容器中
// spring容器中 bean 的信息是用 BeanDefinition 来描述
BeanDefinition beanDefinition = new RootBeanDefinition(SmsEntity.class);
// smsEntity 是 bean id
beanDefinitionRegistry.registerBeanDefinition("smsEntity", beanDefinition);
}
}
@Configuration
@Import(MyImportBeanDefinitionRegistrar.class)
public class MyConfig {
}
基于 FactoryBean 接口注册 bean
// 要注册的类为 MyEntity
public class MyFactoryBean implements FactoryBean<MyEntity> {
@Override
public MyEntity getObject() throws Exception {
return new MyEntity();
}
@Override
public Class<?> getObjectType() {
return MyEntity.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
@Configuration
@Import(MyFactoryBean.class)
public class MyConfig {
}
@Autowired 和 @Resource
@Autowired 和 @Resource 找 bean 的时候根据条件找到的bean必须是唯一的
@Autowired为Spring提供的注解,只按照类型查找。
@Resource为J2EE提供的注解。在该注解中:
-
如果同时指定了name和type,找name和type同时匹配的,找不到则抛出异常。
-
如果指定了name,找name匹配的,找不到则抛出异常。
-
如果指定了type,找type匹配的,找不到或是找到多个,都会抛出异常。
-
如果既没有指定name,又没有指定type,先找name匹配的,此时name是字段属性名;如果没有匹配,找type匹配的。
找name是匹配@Resource里的name属性值和bean的id。
@Primary 和 @Qualifier
public interface Animal {
void sayHi();
}
public class Cat implements Animal{
@Override
public void sayHi() {
System.out.println("cat say hi");
}
}
public class Dog implements Animal{
@Override
public void sayHi() {
System.out.println("dog say hi");
}
}
@RestController
public class MyController {
@Autowired
private Animal animal;
}
假设一个接口有两个实现类,使用 @Autowired 的话会报错。@Autowired 是按照类型查找的。
这时候有两个方案:
-
在 @Autowired 下面或者上面使用 @Qualifier 注解来指定 bean id
-
在 Dog 类 或者 Cat 类上面写 @Primary,表示优先使用这个 bean
java 子父类中的构造函数
在对子类对象进行初始化时,父类的构造函数也会运行,
那是因为子类的构造函数默认的第一行有一条隐式的语句: super();
super():会访问父类中的空参数构造函数。
而且子类中所有的构造函数默认的第一行都是:super();
为什么子类一定要访问父类中的构造函数?
因为父类中的数据子类可以直接获取,所以子类对象在建立时,需要先查看父类是如何对这些数据进行初始化的。
所以子类在对象初始化时,要先访问一下父类中的构造函数。
如果要访问父类中指定的构造函数,可以通过手动定义super语句的方式来指定。
super语句一定定义在子类构造函数的第一行。
子类中所有的构造函数,默认都会访问父类中空参数的构造函数。
因为子类每一个构造函数内的第一行都有一句隐式的super();
当父类中没有空参数的构造函数时,子类必须手动通过super或者this语句形式来指定要访问父类中的构造函数。
子类的构造函数第一行也可以手动指定this语句来访问本类中的构造函数。子类中至少会有一个构造函数会访问父类中的构造函数
Spring Bean 的生命周期
BeanFactory 和 ApplicationContext
Spring 有两个核心接口:BeanFactory 和 ApplicationContext,其中 ApplicationContext 是 BeanFactory 的子接口。他们都可代表 Spring 容器,Spring 容器是生成 Bean 实例的工厂,并且管理容器中的 Bean。
BeanFactory 负责读取 bean 配置文档,管理 bean 的加载,实例化,维护 bean 之间的依赖关系,负责 bean 的生命周期。
ApplicationContext 除了提供上述 BeanFactory 所能提供的功能之外,还提供了更完整的框架功能:
a:国际化支持
b:资源访问
c:事件传递:通过实现 ApplicationContextAware 接口
常用的获取 ApplicationContext 的方法:
a:FileSystemXmlApplicationContext:从文件系统或 url 指定的 xml 配置文件创建,参数为配置文件名或文件名数组
b:ClassPathXmlApplicationContext:从 classpath 的 xml 配置文件创建,可以从 jar 包中读取配置文件
c:WebApplicationContextUtils:从 web 应用的根目录读取配置文件,需要先在 web.xml 中配置,可以配置监听器或者 servlet 来时间
d:AnnotationConfigApplicationContext:是基于注解来使用的,它不需要配置文件,采用 java 配置类和各种注解来配置。
bean 生命周期
这里有图片
aop
什么是 spring aop
spring的aop可以在方法的前后实现增强。aop可以解决我们在程序上的代码冗余问题。
spring aop有哪些应用场景
日志、事务、安全控制、计算方法耗时时间
spring aop的原理
前置通知、后置通知、环绕通知、运行通知、异常通知
aop 的原理
java动态代理模式
maven依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.3</version>
<scope>compile</scope>
</dependency>
aop 五种通知的实现方式
@EnableAspectJAutoProxy
@Configuration
public class MySpringConfig {
}
@Aspect
@Component
public class LogAop {
// 定义切入点:Pointcut 开始方法拦截入口
@Pointcut("execution(* com.pjw..*.*(..))")
public void logAop() {
}
@Before("logAop()")
public void doBefore(){
System.out.println("前置通知 >>> 调用方法之前拦截");
}
@After("logAop()")
public void doAfter(){
System.out.println("后置通知 >>> 调用方法之后拦截");
}
// 后置通知 执行之后 执行运行通知
@AfterReturning("logAop()")
public void doAfterReturning(){
System.out.println("运行通知执行");
}
// 异常通知的时候运行通知不会执行,后置通知 执行之后 执行异常通知
@AfterThrowing("logAop()")
public void doAfterThrowing(){
System.out.println("异常通知执行");
}
@Around("logAop()")
public void doAround(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕通知在方法之前执行");
joinPoint.proceed(); // 执行我们目标方法
System.out.println("环绕通知在方法之后执行");
}
}
@Component
public class OrderService {
public void addOrder(){
System.out.println(111);
}
}
结果:
环绕通知在方法之前执行
前置通知 >>> 调用方法之前拦截
111
环绕通知在方法之后执行
后置通知 >>> 调用方法之后拦截
运行通知执行
手动实现AOP责任链
// 能够把通知链形成关联
public interface MethodInvocation {
void process() throws InvocationTargetException, IllegalAccessException;
}
public class DefaultMethodInvacation implements MethodInvocation {
private List<MethodInterceptor> listMethodInterceptor; // 存放所有的通知
private Object target;// 目标对象
private Method method;// 目标方法
private Object args[];// 目标参数
// 最终使用反射机制执行目标方法
private int index;// 记录当前链调用的位置
public DefaultMethodInvacation(List<MethodInterceptor> listMethodInterceptor, Object target, Method method, Object[] args) {
this.listMethodInterceptor = listMethodInterceptor;
this.target = target;
this.method = method;
this.args = args;
}
public DefaultMethodInvacation(List<MethodInterceptor> listMethodInterceptor) {
this.listMethodInterceptor = listMethodInterceptor;
}
// 调用链形成
public void process() throws InvocationTargetException, IllegalAccessException {
if (index == listMethodInterceptor.size()) {
method.invoke(target, args); // 执行目标
return;
}
MethodInterceptor methodInterceptor = listMethodInterceptor.get(index++);
methodInterceptor.invoke(this);
}
}
public interface MethodInterceptor {
//定义共同通知骨架
void invoke(MethodInvocation methodInvocation) throws InvocationTargetException, IllegalAccessException;
}
public class BeforMethodInterceptor implements MethodInterceptor {
public void invoke(MethodInvocation methodInvocation) throws InvocationTargetException, IllegalAccessException {
System.out.println(">>>>前置通知<<<<");
// 执行我们的目标方法
methodInvocation.process();// 递归调用
}
}
public class AfterMethodInterceptor implements MethodInterceptor {
public void invoke(MethodInvocation methodInvocation) throws InvocationTargetException, IllegalAccessException {
// 执行我们的前置通知
methodInvocation.process();
System.out.println(">>>后置通知<<<");
}
}
public class AroundMethodInterceptor implements MethodInterceptor {
public void invoke(MethodInvocation methodInvocation) throws InvocationTargetException, IllegalAccessException {
System.out.println("环绕通知在目标方法之前执行..");
methodInvocation.process();
System.out.println("环绕通知在目标方法之后执行..");
}
}
public class UserService {
public void login(String userName, Integer age) {
System.out.println("userName:" + userName + ",age:" + age);
}
}
public class Test001 {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
// 1.装配所有的通知存放到集合中
ArrayList<MethodInterceptor> methodInterceptors = new ArrayList<MethodInterceptor>();
methodInterceptors.add(new BeforMethodInterceptor());
methodInterceptors.add(new AfterMethodInterceptor());
methodInterceptors.add(new AroundMethodInterceptor());
// 2.创建我们的目标方法
UserService userService = new UserService();
Method loginMethod = UserService.class.getMethod("login", String.class, Integer.class);
Object[] objects = {"mayikt", 12};
new DefaultMethodInvacation(methodInterceptors, userService, loginMethod, objects).process();
// SpringAop底层 所有的通知最终使用递归算法调用+责任脸设计模式
}
}
aop与事务
手动的事务实现方式
@Component
public class TransactionalUtils {
// 获取当前事务管理器
@Autowired
private DataSourceTransactionManager dataSourceTransactionManager;
public TransactionStatus begin() {
TransactionStatus transaction = dataSourceTransactionManager.getTransaction(new DefaultTransactionAttribute());
System.out.println("获取当前的事务>>>>>");
return transaction;
}
// 提交事务
public void commit(TransactionStatus transactionStatus) {
System.out.println("提交当前的事务>>>>>");
dataSourceTransactionManager.commit(transactionStatus);
}
// 回滚
public void rollback(TransactionStatus transactionStatus) {
System.out.println("回滚当前的事务>>>>>");
dataSourceTransactionManager.rollback(transactionStatus);
}
}
@Service
public class OrderService {
@Autowired
private OrderInfoMapper orderInfoMapper;
@Autowired
private TransactionalUtils transactionalUtils;
public int addOrderInfo(int j) {
TransactionStatus begin = transactionalUtils.begin();
try {
int i = orderInfoMapper.addOrderInfo();
int result = 1 / j;
transactionalUtils.commit(begin);
} catch (Exception e) {
e.printStackTrace();
transactionalUtils.rollback(begin);
}
return 1;
}
}
基于aop封装手动事务
@Aspect
@Component
@Scope("prototype")
public class TransactionalAop {
@Autowired
private TransactionalUtils transactionalUtils;
// 定义切入点
@Pointcut("execution (* com.mayikt.service..*.*(..))")
public void transactionalAop() {
}
// 环绕通知
@Around("transactionalAop()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
// 获取方法名称
String methodName = joinPoint.getSignature().getName();
// 获取目标对象
Class<?> classTarget = joinPoint.getTarget().getClass();
// 获取目标对象类型
Class<?>[] par = ((MethodSignature) joinPoint.getSignature()).getParameterTypes();
// 获取目标对象方法
Method objMethod = classTarget.getMethod(methodName, par);
// 判断该目标方法上是否有加上自定义事务注解
ExtTransactional extTransactional = objMethod.getDeclaredAnnotation(ExtTransactional.class);
if (extTransactional == null) {
return joinPoint.proceed();// 执行目标方法
}
TransactionStatus begin = transactionalUtils.begin();
try {
System.out.println(">>>>环绕通知之前执行...>>>>>>");
Object proceed = joinPoint.proceed();// 执行目标方案
System.out.println(">>>>环绕通知之后执行...>>>>>>");
transactionalUtils.commit(begin);
return proceed;
} catch (Exception e) {
// 目标方法抛出异常的情况下 回滚当前事务
transactionalUtils.rollback(begin);
return 0;
}
// 思考如何回滚呢? 抛出异常
}
}
@Service
public class OrderService {
@Autowired
private OrderInfoMapper orderInfoMapper;
@Autowired
private TransactionalUtils transactionalUtils;
@Transactional
public int addOrderInfo(int j) {
try {
int i = orderInfoMapper.addOrderInfo();
int result = 1 / j;
return 1;
} catch (Exception e) {
e.printStackTrace();
// 手动回滚
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
// 或者自定义抛出异常
return 0;
}
}
// 注意的问题 如果在service 层 抛出异常的情况下 最好使用 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
// 事务原理:当方法执行的时候如果抛出异常的情况 就会回滚当前的事务 如果没有抛出异常 就提交事务
}
基于Spring注解整合JDBC
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
</dependencies>
public class JdbcTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
OrderService orderService = applicationContext.getBean("orderServiceImpl", OrderService.class);
orderService.addOrder();
// 为什么使用事务之后 为什么有把aop给开启呢? 本身就是基于AOP实现的
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (int i = 0; i < beanDefinitionNames.length; i++) {
System.out.println(beanDefinitionNames[i]);
}
}
}
@Configuration
@ComponentScan("com.mayikt")
@EnableTransactionManagement
public class MyConfig {
// 学习xml ssh spring-jdbc.xml
//注入到ioc容器中 beanid =dataSource class=DataSource类的完整路径地址
// 配置我们的数据源
@Bean
public DataSource dataSource() {
MysqlDataSource mysqlDataSource = new MysqlDataSource();
mysqlDataSource.setUser("root");
mysqlDataSource.setPassword("root");
mysqlDataSource.setURL("jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8");
mysqlDataSource.setDatabaseName("test");
return mysqlDataSource;
}
// @EnableTransactionManagement 实际上帮助我们开启了aop
/**
* 注入JdbcTemplate
*
* @return
*/
@Bean
public JdbcTemplate jdbcTemplate() {
return new JdbcTemplate(dataSource());
}
// 多数据源如何实现
//@EnableTransactionManagement 开启事务注解
@Bean
public PlatformTransactionManager platformTransactionManager(){
return new DataSourceTransactionManager(dataSource());
}
// 完全高仿springboot框架
}
@Repository
public class OrderDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public void addOrder() {
jdbcTemplate.update("insert into order_info values(null,'mayikt','zhangsan','1111')");
}
}
public interface OrderService {
void addOrder();
}
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private OrderDao orderDao;
@Transactional
public void addOrder() {
try {
orderDao.addOrder();
int i = 1 / 0; // 如果报错的情况下肯定是会插入到数据库中
} catch (Exception e) {
}
}
// springboot-jdbc
}
循环依赖
循环依赖概念
依赖注入:赋值
@Service
//@Scope("prototype")
public class AService {
//
@Autowired
public BService bService;
// 为什么Aservice在创建的时候 为什么Bservice比ASERVICE 先创建
public AService() {
System.out.println("AService被Java的反射技术创建");
}
public void setbService(BService bService) {
this.bService = bService;
}
}
@Service
//@Scope("prototype")
public class BService {
@Autowired
public AService aService;
public void setaService(AService aService) {
this.aService = aService;
}
}
Spring 中的循环依赖问题在单例的情况下,Spring 是已经帮助我们解决好了。多例情况下,是无法解决循环依赖问题。
解决多例中的循环依赖
public class SpringApp {
public static void main(String[] args) {
// 1. ioc容器在创建的时候所有的单例对象是不是会被创建
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext(MyConfig.class);
// // 对例子情况 当你在调用的时候才获取
// AService aSerivce = applicationContext.getBean("AService", AService.class);
BService bSerivce = applicationContext.getBean("BService", BService.class);
// aSerivce.setbService(bSerivce);
// bSerivce.setaService(aSerivce);
// 循环引用异常 找不到对象
/**
* 思考问题? 如果我们的项目对象必须要是多例? 而且必须要循环引用 明确的指定引用那个对象
*/
// String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
// for (int i = 0; i < beanDefinitionNames.length; i++) {
// System.out.println(beanDefinitionNames[i]);
// }
/**
* spring中单例的情况下 实际上已经帮助我们解决好了这样循环依赖问题
*
* 分析Spring单例 循环依赖的问题底层是如何解决的?
* 单例对象在什么时候被创建。 IOC容器被加载的时候创建 多例子的情况下 是在调用的时候创建
*/
// 缓存我们的婴儿对象
HashMap<String, Object> stringObjectHashMap = new HashMap<String, Object>();
stringObjectHashMap.put("aService", new AService());
stringObjectHashMap.put("bService", new BService());
// 3.从三级缓存中查询到赋值
AService aService = (AService) stringObjectHashMap.get("aService");
BService bService = (BService) stringObjectHashMap.get("bService");
aService.bService = bService;
// Java的引用传递
bService.aService = aService;
}
}

浙公网安备 33010602011771号