文章目录
Ⅰ、AOP简述
非常nice的链接——👇👇👇👇👇
1、AOP
2、静态、动态代理
3、ThreadLocal
AOP:Aspect-Oriented Programming 面向切面编程 面向切面(AOP)编程,是对面向对象(OOP)编程的补充。不改变源代码的情况下,加入额外(比如是否开启校验等)的功能。
面向切面:从左往右,横向编程切入(插队);切面:aspect(通知+切点)
面向对象:自上而下,纵向编程(一步一步的来);对象:类
截图——
使用动态代理来实现“加入”额外功能,介绍动态代理之前,先了解静态代理。
使用案例说明——张三给李四转账100元
正常操作之前
正常操作之后
如果中间出现异常,可能会导致张三少了100元,但是李四的钱没有增加等。那么这就是不可取逻辑操作(正常情况下,如果操作失败,张三的钱没有少,李四的钱没有多),那么我使用静态代理,手动给转账操作加上事务(操作失败就回滚~)
零、代理
代理,中间商一样的存在【待补充】
一、静态代理
静态静态就是不可变的意思【待补充】
1、创建一个关于事务的工具类(开启事务、提交事务、事务回滚)
TransactionManager.java
package com.hbw.util;
import java.sql.Connection;
import java.sql.SQLException;
public class TransactionManager {
/*开启事务*/
public static void startTransaction(Connection connection){
try {
System.out.println("开启事务");
connection.setAutoCommit(false);
} catch (SQLException e) {
e.printStackTrace();
}
}
/*提交事务*/
public static void commitTransaction(Connection connection){
try {
System.out.println("提交事务");
connection.commit();
} catch (SQLException e) {
e.printStackTrace();
}
}
/*事务回滚*/
public static void rollbackTransaction(Connection connection){
try {
System.out.println("事务回滚");
connection.rollback();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
2、使用切面编程的思想添加事务(给原本的操作加上事务的补充操作)
TransactionServiceImpl.java
package com.hbw.service;
import com.hbw.util.JdbcConnection;
import com.hbw.util.TransactionManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import java.sql.Connection;
@Service("transactionServiceImpl")
public class TransactionServiceImpl implements MoneyService {
@Autowired
@Qualifier("moneyServiceImpl")
private MoneyServiceImpl moneyService;
public TransactionServiceImpl() {
}
public TransactionServiceImpl(MoneyServiceImpl moneyService) {
this.moneyService = moneyService;
}
public MoneyServiceImpl getMoneyService() {
return moneyService;
}
public void setMoneyService(MoneyServiceImpl moneyService) {
this.moneyService = moneyService;
}
@Override
public void payment(int first, int second, int mmoney) {
Connection connection = JdbcConnection.getConnection();
//开启事务
TransactionManager.startTransaction(connection);
try{
moneyService.payment(first,second,mmoney);
TransactionManager.commitTransaction(connection);
}catch (Exception e){
e.printStackTrace();
TransactionManager.rollbackTransaction(connection);
} finally {
JdbcConnection.colseConnection(connection);
}
}
}
二、动态代理
动态动态,可以根据不同的类,动态的匹配,并为其添加补充功能(代理就是起个加强补充的效果)
引用别人的图片来说明——详解👉https://www.cnblogs.com/cC-Zhou/p/9525638.html
1、JDk动态代理
1)实现InvocationHandler接口
ProxyAutoManeger.java
package com.hbw.util;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class ProxyAutoManeger implements InvocationHandler {
private Object pro;
public ProxyAutoManeger() {
}
public ProxyAutoManeger(Object pro) {
this.pro = pro;
}
public Object getPro() {
return pro;
}
public void setPro(Object pro) {
this.pro = pro;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("添加了一个某某功能");
//被代理的类(如果被代理的类调用的方法有返回值,需要return)
return method.invoke(pro,args);
}
}
2)测试
@Test
public void test3(){
//传入指定的实现类
MoneyDaoImpl moneyDaoImpl = new MoneyDaoImpl();
InvocationHandler invocationHandler = new ProxyAutoManeger(moneyDaoImpl);
MoneyDao proxyMoney = (MoneyDao) Proxy.newProxyInstance(moneyDaoImpl.getClass().getClassLoader(),moneyDaoImpl.getClass().getInterfaces(),invocationHandler);
Countmoney ct = proxyMoney.getCountmoneyById(1);
System.out.println(ct);
}
3)结果
打印:
①添加了一个某某功能
②Countmoney{midd=1, mname=‘张三’, mmoney=600.0}
解释:
①是我添加的功能(这里的功能就只是打印了一句话,你可以设置其他复杂的功能)
②是我这个实现类本身实现的功能(根据传入的id查询指定的消息)
说明:
这里我通过JDk自带的接口InvocationHandler,实现了动态代理——为查询结果添加一句话。
其实看开始状态和结果,你会发现代理就只是对预设的代码进行了补充。不过动态代理能根据你传入的实现类不同,而给不同的实现类进行补充
2、CGLIB动态代理
实现接口MethodInterceptor ,原理同JDK的动态代理
1)创建动态代理工具类
CGLIBProxyManeger .java
package com.hbw.util;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
//注意MethodInterceptor 的包
public class CGLIBProxyManeger implements MethodInterceptor {
private Object pro;
public CGLIBProxyManeger() {
}
//用于初始化pro属性
public CGLIBProxyManeger(Object pro) {
this.pro = pro;
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("使用CGLIB动态代理实现了某某功能");
return method.invoke(pro,objects);
}
}
2)测试
@Test
public void test(){
//获取工厂对象
Enhancer enhancer = new Enhancer();
//创建被代理的实例
MoneyDaoImpl moneyDaoImpl = new MoneyDaoImpl();
enhancer.setSuperclass(moneyDaoImpl.getClass());
enhancer.setCallback(new CGLIBProxyManeger(moneyDaoImpl));
//创建动态代理后的实例(实际执行者)
MoneyDao cglibProxyMoneyDao = (MoneyDao) enhancer.create();
System.out.println(cglibProxyMoneyDao.getCountmoneyById(1));
}
三、AOP实现原理
【总结代理,待补充】
Ⅱ、应用AOP
其实就是动态代理,在指定位置添加指定功能,over!!!
前提,导入两个jar包
<!--spring-aop-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.1.7.RELEASE</version>
</dependency>
1、xml使用AOP 0
1)定义通知(额外加入的功能)
注意:目标方法有返回值时,环绕通知需要设置返回值
Notice.java
package com.hbw.util;
import com.hbw.bean.Countmoney;
import org.aspectj.lang.ProceedingJoinPoint;
public class Notice {
public void before1(){
System.out.println("目标方法前的通知");
}
public void after1(){
System.out.println("目标方法后的通知");
}
public Countmoney aroud1(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("目标方法环绕前置通知");
//用于前后分界啦
Countmoney countmoney = (Countmoney) proceedingJoinPoint.proceed();
System.out.println("目标方法环绕后置通知");
return countmoney;
}
public void return1(){
System.out.println("目标方法返回时的通知");
}
public void exception1(){
System.out.println("目标方法异常时的通知");
}
}
2)配置xml
ApplicationContext.xml
<!--初始化通知工具类-->
<bean id="notice" class="com.hbw.util.Notice"></bean>
<!--配置aop-->
<aop:config>
<!--d定义切点:要切开的地方,就是要添加额外功能的地方-->
<!--execution中的*表示:返回值类型 ;方法名中的..表示:任意参数列表(可变参数列表)-->
<aop:pointcut id="pcut" expression="execution(* com.hbw.dao.MoneyDaoImpl.*(..))"/>
<!--定义切面-->
<aop:aspect ref="notice">
<aop:before method="before1" pointcut-ref="pcut"></aop:before>
<aop:after method="after1" pointcut-ref="pcut"></aop:after>
<aop:around method="aroud1" pointcut-ref="pcut"></aop:around>
<aop:after-returning method="return1" pointcut-ref="pcut"></aop:after-returning>
<aop:after-throwing method="exception1" pointcut-ref="pcut"></aop:after-throwing>
</aop:aspect>
</aop:config>
3)测试
注意:需要依赖注入被代理的类,不要手动实例化(就是不要手动new,不然实例的还是原本的、没有被加强的实例)
StudentTest.java
import com.hbw.bean.Countmoney;
import com.hbw.dao.MoneyDao;
import com.hbw.dao.MoneyDaoImpl;
import com.hbw.service.MoneyService;
import com.hbw.util.CGLIBProxyManeger;
import com.hbw.util.ProxyAutoManeger;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public class MoneyTest {
@Autowired
private MoneyDao moneyDao;
/*测试xml实现aop*/
@Test
public void test5() {
System.out.println(moneyDao.getCountmoneyById(1));
}
}
4)结果
目标方法前的通知
目标方法环绕前置通知
目标方法返回时的通知
目标方法环绕后置通知
目标方法后的通知
Countmoney{midd=1, mname='张三', mmoney=600.0}
2、注解使用AOP
1、定义通知,添加注解@Aspect
@Component
@Aspect
public class LoggerAdviser {
@Pointcut("execution(void com.offcn.service.AccountServiceImpl.walk())")
public void pc(){
}
@Before("pc()")
public void beforeLog(){
System.out.println("我是目标方法前的通知");
}
@After("pc()")
public void afterLog(){
System.out.println("我是目标方法后的通知");
}
@Around("pc()")
public void aroudLog(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("我是目标方法环绕前置通知");
proceedingJoinPoint.proceed();
System.out.println("我是目标方法环绕后置通知");
}
@AfterReturning("pc()")
public void returnLog(){
System.out.println("我是目标方法返回时通知");
}
@AfterThrowing("pc()")
public void exceptionLog(){
System.out.println("我是目标方法异常时通知");
}
}
2、在配置文件中启动动态代理注解配置:
<context:component-scan base-package="com.**"></context:component-scan>
<!--启动注解配置动态代理-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
Ⅲ、事务
一、事务
二、spring中事务的配置
1、xml配置
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="transfer" isolation="READ_COMMITTED" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="txpc" expression="execution(* com.offcn.service.AccountServiceImpl.transfer(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txpc"></aop:advisor>
</aop:config>
2、注解配置
1)配置文件中初始化事务和加事务注解驱动:
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--开启事务注解驱动-->
<!-- <tx:annotation-driven></tx:annotation-driven>-->
2)在需要添加事务的方法上加注解@Transactional
三、spring整合mybatis
👉spring——maven项目中spring整合mybatis
疑惑
1、Aop
2、静态动态代理
3、ThreadLocal是怎么保证只有一个连接的?