Spring基础
Spring AOP
AOP概念:面向切面编程(Aspect Oriented Programming)。指在程序运行期间,将某段代码动态的切入到指定方法的指定位置进行运行的这种编程方式,叫面向切面编程。
- JDK动态代理
基于JDK Proxy的动态代理接口的AOP实现
1 public interface Calculator { 2 int add(int i, int j); 3 int sub(int i, int j); 4 int mul(int i, int j); 5 int div(int i, int j); 6 }
1 import com.primary.test.aop.inter.Calculator; 2 3 public class MyMathCalculator implements Calculator { 4 5 @Override 6 public int add(int i, int j) { 7 System.out.println(" i + j = " + (i + j)); 8 return i + j; 9 } 10 11 @Override 12 public int sub(int i, int j) { 13 return i - j; 14 } 15 16 @Override 17 public int mul(int i, int j) { 18 return i * j; 19 } 20 21 @Override 22 public int div(int i, int j) { 23 return i / j; 24 } 25 }
2 3 import com.primary.test.aop.inter.Calculator; 4 5 import java.lang.reflect.InvocationHandler; 6 import java.lang.reflect.Method; 7 import java.lang.reflect.Proxy; 8 import java.util.Arrays; 9 10 public class CalculatorProxy { 11 12 /** 13 * @param calculator 被代理对象 14 * @return 15 */ 16 public static Calculator getProxy(final Calculator calculator) { 17 ClassLoader classLoader = calculator.getClass().getClassLoader(); 18 Class<?>[] interfaces = calculator.getClass().getInterfaces(); 19 InvocationHandler handler = new InvocationHandler() { 20 /** 21 * 22 * @param proxy 23 * @param method 24 * @param args 25 * @return 26 * @throws Throwable 27 */ 28 @Override 29 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 30 // 利用反射执行目标方法 31 // 目标方法的执行后的返回值 32 System.out.println("动态代理在执行方法..."); 33 Object result = null; 34 try { 35 System.out.println("【" + method.getName() + "】方法在执行,方法参数是:" + Arrays.asList(args)); 36 result = method.invoke(calculator, args); 37 System.out.println("【" + method.getName() + "】方法正常执行完毕,计算结果是:" + result); 38 } catch (Exception e) { 39 System.out.println("方法【" + method.getName() + "】执行有异常,原因是" + e.getCause()); 40 } finally { 41 System.out.println("【" + method.getName() + "】方法finally执行完毕"); 42 } 43 // 返回目标方法,外界才能感受到 44 return result; 45 } 46 }; 47 Object proxy = Proxy.newProxyInstance(classLoader, interfaces, handler); 48 return (Calculator) proxy; 49 } 50 }
JDK动态代理缺点:
1) 写起来复杂;
2) JDK默认的动态代理,如果目标对象没有实现任何接口,是无法为他创建代理对象的。
-
Spring AOP实现步骤
- pom.xml中添加spring-aspects.jar maven依赖
<properties> <!--SpringVersions--> <spring.version>4.3.6.RELEASE</spring.version> </properties> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>${spring.version}</version> </dependency>
2. 把目标类和代理类添加到容器中:目标类上添加@Service,切面类上添加@Component,在spring的配置文件applicationContext.xml中添加包扫描配置<context: package-sacn base-package="com.***"/>
告诉Spring哪个是切面:再在切面类上添加注解@Aspect
切面类的方法在什么时候哪个方法去执行:在切面类的方法上面添加注解
@Before 前置通知
@AftterReturn 返回通知
@AfterThrowing 异常通知
@After 后置通知
@Around 环绕通知,是前四种的组合形式
3. 再在spring的配置文件applicationContext.xml中添加基于注解的aop配置<aop: aspectj-autoproxy></aop: aspectj-autoproxy>
Spring注解
@Qualifier:当一个接口中有两个或以上的实现类时,Spring无法区分需要自动装配哪个类,则需要用@Qualifier注解来区分Spring容器管理的bean。比如以下的SomeServiceImpl和OtherServiceImpl均实现SomeService,则在测试类ApplicationTests 中则要用@Qualifier("bean name")来注解接口类SomeService。
1 import com.abc.service.SomeService; 2 import org.springframework.stereotype.Service; 3 4 @Service 5 public class SomeServiceImpl implements SomeService { 6 @Override 7 public void doSome() { 8 System.out.println("执行dosome()的方法"); 9 } 10 }
1 import com.abc.service.SomeService; 2 import org.springframework.stereotype.Service; 3 4 @Service 5 public class OtherServiceImpl implements SomeService { 6 @Override 7 public void doSome() { 8 System.out.println("执行othersome 的dosome方法"); 9 } 10 }
1 import com.abc.service.SomeService; 2 import org.junit.jupiter.api.Test; 3 import org.springframework.beans.factory.annotation.Autowired; 4 import org.springframework.beans.factory.annotation.Qualifier; 5 import org.springframework.boot.test.context.SpringBootTest; 6 7 @SpringBootTest 8 class ApplicationTests { 9 10 // 若接口只有一个实现类,则使用bytype方式自动注入 11 // 若接口有两个实现类,则只能使用byname方式自动注入 12 @Autowired 13 @Qualifier("someServiceImpl") 14 private SomeService someService; 15 16 @Autowired 17 @Qualifier("otherServiceImpl") 18 private SomeService otherService; 19 20 @Test 21 void contextLoads() { 22 someService.doSome(); 23 otherService.doSome(); 24 } 25 26 }
Spring事务
事务的概念:指的时逻辑上的一组操作,组成事务的各个单元要么一起成功,要么一起失败。
事务的特性(ACID)
- 原子性(Atomicity)
- 一致性(Consistency)
- 隔离性(Isolation)
- 持久性(Durability)
事务并发的问题(隔离性导致)
- 脏读:一个事务读到了另一个事务未提交的数据。
- 不可重复读:一个事务读取到另一个事务已经提交的数据,导致对同一条数据前后读取的结果不一致。update操作。
- 幻读:一个事务读取另一个事务已提交的数据,导致对同一张表读取两次以上的结果不一致。insert,delete操作。
事务的隔离级别
为了避免以上并发导致的问题,在标准的SQL规范中,定义了4个事务隔离级别。不同的隔离级别对不同的事务处理不同。
- 四种隔离级别
MySQL为我们提供的四种隔离级别(由低到高)
事务管理方式
- 编程式事务管理
- 声明式事务管理
编程式事务管理使用TransactionTemplate(Spring推荐的编程式事务)或者更底层的PlatformTransactionManager。
声明式事务管理建立在AOP之上。其本质是在目标方法前后进行拦截,在目标方法开始之前新建或者加入一个事务,在目标方法执行完之后,根据实际情况提交或者回滚事务。声明式事务管理也分两种形式,一种是基于tx和aop名字空间的xml配置文件方式,另一种是基于@Transactional注解,注解方式更简单易用清爽。
xml方式的声明式事务管理
第一步:在spring配置文件中,配置平台事务管理器。Spring针对不同的持久化框架,提供了PlatformTransactionManager接口的不同的实现类,这里采用的是DataSourceTransactionManager。<!-- 配置平台事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 注入数据源 -->
<property name="dataSource" ref="dataSource"/> </bean>
第二步:配置事务通知
<!-- 事务通知 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="transform*"/> <!-- 提交订单 --> <tx:method name="submitOrder"/> <!-- 添加 --> <tx:method name="add*"/> <tx:method name="insert*"/> <!-- 删除 --> <tx:method name="delete*"/> <tx:method name="remove*"/> <!-- 修改 --> <tx:method name="update*"/> <tx:method name="modify*"/> <!-- 查询 --> <tx:method name="query*" read-only="true" isolation="REPEATABLE_READ"/> <tx:method name="find*"/> <tx:method name="get*"/> </tx:attributes> </tx:advice>
第三步:配置AOP
<!-- 配置AOP --> <aop:config> <aop:advisor advice-ref="txAdvice" pointcut="execution(* cn..service.*.*(..))"/> </aop:config>
注解方式的声明式事务管理方式
第一步:添加平台事务管理器,并开启注解式事务
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 注入数据源 -->
<property name="dataSource" ref="dataSource"/> </bean>
<!-- 开启注解式事务 --> <tx:annotation-driven transaction-manager="transactionManager"/>
第二步:在业务层接口实现类或者实现方法上,添加@Transactional注解
参考博文:https://blog.csdn.net/mingyundezuoan/article/details/79017659