spring(三)——AOP(代理、AOP的应用、事务)

Ⅰ、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是怎么保证只有一个连接的?


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈年_H

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值