SpringAOP和事务

springAOP面向切面编程

1:aop编程思想以及aop的实现
1:什么是aop
  1. 什么是oop

是:是将开发中遇到的客观现实的物件抽象成属性、方法并放入模板(类)中的一种编程思想

三大特生就是 封装 继承 多态 (他们都是基于抽象实现的)

  1. 什么是aop

是:是把纵向的oop的非核心的但是多个类中存在的重复的代码逻辑,抽取出来放到一个代理对象中的编程思想,例如每个类中都需要关闭io的操作,造成了代码大量的冗余,我很横向的抽取出来放到一个代理对象中,用的时候切入引用就可以了

只负责核心代码,抽取出来的代码用代理对象处理非核心但是需要的代码功能

2:aop思想的设计的7个核心概念
  1. 连接点 连接点(Joinpoint):每个目标代理的方法
  2. 切入点(pointcut) 一个类中有多个连接点,这些连接点被称为切点
  3. 增强(advice) 就是不改类内容的情况下对类功能的补充
  4. 目标对象(target) 目标代理的对象
  5. 织入 (weaving)就是蒋增强添加到目标
  6. 代理(proxy) 增强了的对象
  7. 切面 切点切入后,加上代理就形成了切面
3:spring aop 实现原理

​ 所说的aop面向切面编程,也就是将核心关注点意外的可以复用的提取出来,通过

aop技术,在程序运行起来时候动态的增强的代码切入到目标中,在这个过程中会产生一个代理对象,

代理对象有着原来方法和能力的,而且增加了新功能

1:静态代理

静态代理:

装饰者模式 连接池的连接,

Connection.close();

在不改变原有代码情况下,直接使用装饰者模式生成一个新的对象!

动态代理:

在代码运行起来时,动态的修改原有类的方法内容,不需要预先设计好代理类

​ 装饰者模式:

2:JDK代理

​ 在代码运行起来时候,动态的生成增强的代码,不需要预先创建好代理类

JDK:类似于静态代码的方式!只不过会动态的生成一个代理类!再生成代理对象!
要求目标类必须实现了’接口’!

具体实现:

要求有接口

有接口实现类 实现接口的方法

测试代理:

public class JDKproxy {
@Test
public void testProxy(){
  //创建目标对象
  Student student = new StudentImpl();
  //创建代理对象     传入目标代理的参数类加载器        类接口     内部类
  Student student1 = (Student) Proxy.newProxyInstance(student.getClass().getClassLoader(), student.getClass().getInterfaces(), new InvocationHandler() {
      /**
             * 
             * @param proxy   代理对象
             * @param method   目标方法
             * @param args  目标方法参数
             * @return  代理对象方法的返回值
             * @throws Throwable
       */
      @Override
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
          //之前添加
          System.out.println("添加增强功能前");
          Object invoke = method.invoke(student, args);
          //之后
          System.out.println("添加目标执行后");
          return invoke;
      }
  });
  //调用代理对象
  student1.eat();
}
}
3:CGlib代理

cglib一种动态拦截方法生成的技术!他不会额外生成类!在代码编译的时候动态改变原来类的字节码文件!
生成代理对象! student --> student --> 增强 --> 代理对象!

cglib不要求目标类必须实现接口!

1://创建代理类
public class Student {
public void run(){
  System.out.println("Student.run");
}
}
2:创建增强类增强方法
public class MyAdvice {
public void before(){
  System.out.println("MyAdvice.before");
}
public void after(){
  System.out.println("MyAdvice.after");
}
}
3:创建拦截
public class MyInterceptor implements MethodInterceptor {

@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
  //创建增强
  MyAdvice myAdvice = new MyAdvice();
  myAdvice.before();
  //目标
  Object o1 = methodProxy.invokeSuper(o, objects);
  myAdvice.after();
  return o1;
}
}
测试
public class CglibTest {
@Test
public void testCglib(){
  //创建拦截
  MyInterceptor myInterceptor = new MyInterceptor();
  Enhancer enhancer = new Enhancer();
  enhancer.setCallback(myInterceptor);
  enhancer.setSuperclass(Student.class);
  Student student = (Student) enhancer.create();
  student.run();
}
}

spring aop会自动根据情况进行底层实现的切换! 优先是jdk动态代理!如果没有接口只需要向项目中导入
cglib依赖会自动切换!

对比JDK CGLIB

jdk是jdk内置的代理,不需要导入第三方依赖,jdk要求有共同接口的存在,用增强对象执行方法,动态添加增强功能

cglib不需要接口,但是需要一个拦截器,在拦截器里面执行目标方法,执行前后添加增强方法

4: aop基于xml配置

第一步:导入依赖

spring-aop
spring-aspect
aopalliance
aspectjweaver

第二步:目标类

service类

第三步:写增强

每个增强方法(除了环绕)中都有一个Jionpoint参数,为了获取目标代理方法的一些信息,另外afterReturning方法中有一个Throwable参数,为了获取异常的信息,在添加注解时要注意添加方式

环绕通知:返回值Object,返回执行的目标方法

参数proceeding JionPoint

afterThrowing(JoinPoint joinPoint,Throwable throwable)方法
/**
     * Throwable throwable 只能作为错误通知传递!
     * joinPoint 除了环绕都可以传递
     * @param joinPoint  连接点,除了环绕其他方法都有连接点
     * @param throwable 给你一个对象 让你获取错误信息
     */
    //import org.aspectj.lang.JoinPoint;
    public void returnException(JoinPoint joinPoint,Throwable throwable){

        //记住 环绕通知是切点!其他的通知都有连接点!可以写 可以不写!
        //写是为方便获取目标类和方法的信息

        String name = joinPoint.getSignature().getName();
        String name1 = joinPoint.getTarget().getClass().getName();

        String message = throwable.getMessage();

        System.out.println("发送邮件");
        System.out.println("类:"+name1+" 方法:"+name+" 错误内容:"+message);
    }

第四部:写配置

<!--第一步:扫描包-->
    <context:component-scan base-package="com.it.dao.impl,com.it.service.impl,
com.it.controller,com.it.advice"></context:component-scan>
<!--第二步:切点配置-->
<!--开启种事务-->
<aop:config>
        <aop:pointcut id="pc" expression="execution(* 					com..service.impl.*Impl.*(..))">
    	</aop:pointcut>
        <aop:aspect ref="accountAdvice">
            <aop:before method="before" pointcut-ref="pc">				</aop:before>
            <aop:after-returning method="afterReturning" 					pointcut-ref="pc"></aop:after-returning>
            <aop:after-throwing method="afterThrowing" 						pointcut-ref="pc"></aop:after-throwing>
            <aop:after method="after" pointcut-ref="pc">				</aop:after>
        </aop:aspect>
</aop:config>

第五步:测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")//测试环境
public class AccountTest {
    @Autowired
    private AccountController accountController;
    @Test
    public void testAccount(){
        accountController.transfer("zhangsan", "lisi", 5000);
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4gUkfZoN-1572167116111)(C:\Users\32302\Desktop\typora\img\测试.PNG)]

5:aop基于注解的配置

步骤1:导包
步骤2:目标类
步骤3:增强类

  	  	         1: 在增强类上面ioc容器管理  @Component
  	  	          切面的注解   @Aspect

  	  	         2:配置切点方法
  	  	   		  @Pointcut("execution(表达式)")
  	  	            public void xxx(){}

  	  	          避免后面重复写表达式切点!

  	  	          3:方法上配置对应的切点

  	  	         @Before(切点表达式 1.直接execution(表达式) 

​ 2.可以引用声明的切点 “类名.切点方法()”);
@After();
@Around();
@AfterReturning();
@AfterThrowing(pointcut=,throwing=“异常参数名称”)

  	           4:开启注解形式aop的支持

  	  		   配置文件中
  	  		   <aop:aspectj-autoproxy  />
6: aop练习

转账业务:

。。。

spring数据库数据库相关 事务

1. 回顾什么是数据库事务

数据库事务是数据库执行的逻辑单位,为了保证数据额安全性,我们要保证这个逻辑单位的完全失败执行或者

完全成功执行

#### 2. 数据库的acid 特性

a:原子性

c:持久性

i:隔离性

d:一致性

#### 3. 事物的隔离性

四个隔离级别

read uncommited

read commieted

repeat  read

serializable

#### 4. 不同级别的隔离会导致什么问题

#### 5. spring数据库事务的实现和涉及的包

spring 事务的实现

一个增强

一个事务管理接口

三个事务管理器的实现类

##### spring-jdbc:

DatasourceTrasactionManager

			实现的持久层技术  JdbcTemplate     Dbutils      原生的jdbc      myBatis    都操作connection

##### spring-tx:

			事物的增强

			事务管理的接口   PlateFormTrasactionManager

##### spring-orm(整合第三方的orm类型的持久层框架)

JpaTrasactionManager

HibernateTrasactionManager

2. spring 事务步骤 -----xml

步骤一:导包

事务:spring-tx

代理:cglib

spring-aop,spring-aspects,aopalliance,aspectjweaver

用到spring四个核心依赖

spring -aop

数据库:MySQL c3p0 spring-jdbc

步骤二:java核心代码(转账过程能运行起来)
步骤三:编写增强
@Component
public class AccountAdvice {
   
    public void before(JoinPoint joinPoint){
        //开启事务
        System.out.println("开启事务");
    }

    public void afterReturning(){
        //事务成功,提交事务
        System.out.println("提交");
    }

    public void afterThrowing(JoinPoint joinPoint,Throwable throwable){
        //有异常回滚
        System.out.println("回滚");
    }
   
    public void after(){
        //关闭
        System.out.println("关闭");
    }
    //环绕
    public Object round(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("前");
        Account proceed = (Account) joinPoint.proceed();//目标方法
        System.out.println("后");
        return proceed;
    }
}
    
步骤四编写xml
   <!--扫描-->
    <context:component-scan base-package="com.it.dao.impl,com.it.service.impl,
com.it.controller,com.it.advice"></context:component-scan>


    <!--c3p0-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"></bean>
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!--开启种事务-->
    <aop:config>
        <aop:pointcut id="pc" expression="execution(* com..service.impl.*Impl.*(..))"></aop:pointcut>
        <aop:aspect ref="accountAdvice">
            <aop:before method="before" pointcut-ref="pc"></aop:before>
            <aop:after-returning method="afterReturning" pointcut-ref="pc"></aop:after-returning>
            <aop:after-throwing method="afterThrowing" pointcut-ref="pc" throwing="throwable"></aop:after-throwing>
            <aop:after method="after" pointcut-ref="pc"></aop:after>
        </aop:aspect>
    </aop:config>

运行结果如上图

3: spring事务管理使用步骤 annotation

	<!--扫描-->
    <context:component-scan base-package="com.it.dao.impl,com.it.service.impl,
					com.it.controller,com.it.advice"></context:component-scan>


    <!--c3p0    并持久层注入jdbcTemplate-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"></bean>
	<!--jdbcTemplate中传入c3p0-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
<!--注解申明-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

增强类:

@Component
@Aspect
public class AccountAdvice {
    //切点方法
    @Pointcut("execution(* com..service.impl.*Impl.*(..))")
    public void asp(){

    }
    @Before("AccountAdvice.asp()")
    public void before(JoinPoint joinPoint){
        //开启事务
        System.out.println("开启事务");
    }
    @AfterReturning("AccountAdvice.asp()")
    public void afterReturning(){
        //事务成功,提交事务
        System.out.println("提交");
    }
    @AfterThrowing(value = "AccountAdvice.asp()",throwing = "throwable")
    public void afterThrowing(JoinPoint joinPoint,Throwable throwable){
        //有异常回滚
        System.out.println("回滚");
    }
    @After("AccountAdvice.asp()")
    public void after(){
        //关闭
        System.out.println("关闭");
    }
    //环绕
    @Around("AccountAdvice.asp()")
    public Object round(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("前");
        Account proceed = (Account) joinPoint.proceed();//目标方法
        System.out.println("后");
        return proceed;
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KvELJrYq-1572167116113)(C:\Users\32302\Desktop\typora\img\注解.PNG)]

步骤一:在目标方法或者目标类上使用注解申明

@Transactional

@Transactional(isolation=Isolation.READ_COMMITED,propatation=Propatation.SUPORTS,readOnly=true,timeOut=30)

作用位置:类或者方法上

注意:如果添加在类上,类中所有方法均被开启事务,如果只添加在方法上面,则

支队本方法生效,如果类上和方法上都有添加则在方法杀不过面的有效

属性中少了name属性,因为直接作用在具体位置上面的。

编写配置文件

<!--步骤一根据持久层框架选择事务管理器的实现类-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!--步骤二:配置自配的增强-->
    <tx:advice id="advice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="find*" read-only="false" timeout="30" propagation="REQUIRED" isolation="READ_COMMITTED"/>
            <tx:method name="select*" read-only="false" timeout="30" propagation="REQUIRED" isolation="READ_COMMITTED"/>
            <tx:method name="query*" read-only="false" timeout="30" propagation="REQUIRED" isolation="READ_COMMITTED"/>
            <tx:method name="modify*" read-only="false" timeout="30" propagation="REQUIRED" isolation="READ_COMMITTED"/>
            <tx:method name="transfer*" read-only="true" timeout="30" propagation="REQUIRED" isolation="READ_COMMITTED"/>
            <tx:method name="drop*" read-only="false" timeout="30" propagation="REQUIRED" isolation="READ_COMMITTED"/>
            <tx:method name="*" ></tx:method>
        </tx:attributes>
    </tx:advice>
    <!--步骤三:配置aopconfig-->
    <aop:config>
        <aop:pointcut id="pc" expression="execution(* com..service.impl.*Impl.*(..))"></aop:pointcut>
        <aop:advisor advice-ref="advice" pointcut-ref="pc"></aop:advisor>
     </aop:config>

解释:expression="execution(* com…service.impl.Impl.(…))

第一个* 代表所代理的目标方法访问类型是任意类型,
两个…代表忽略中间包的任意数量层级,
第二个代表一Impl结尾的类,
括号前面的
代表任意方法
括号中的两个点代表任意数量类型的方法参数

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值