spring03:AOP(下)、事务控制(上)


第二部分:AOP面向切面编程(下)


一、异常通知

异常通知:切入点方法发生异常后才会执行该切面方法。注意异常通知后置通知是矛盾的,不能既执行异常通知又执行后置通知。

1. DeptDao——切入点方法

package com.dao;

import org.springframework.stereotype.Repository;

@Repository
public class DeptDao {
    public Integer insert(String dname) {
        System.out.println(dname + "插入成功!");
        // 在这里设置异常,检测到异常后会出发异常通知
        System.out.println(100/0);
        return 1;
    }
}

2. DmlAspect——切面方法

含义/作用
@AfterThrowing异常通知注解
pointcut用来指定切入点表达式
execution切入点表达式,用来指定切入点
throwing用来获取异常对象
afterException自定义的异常通知的切面方法
JointPoint切入点对象
Throwable异常对象
	// 异常通知的切面方法
    @AfterThrowing(pointcut = "execution(* com.dao.*.*(*))", throwing = "e")
    public void afterException(JoinPoint point, Throwable e) {
        System.out.println("***************异常通知***********************");
        System.out.println("切入点发生的异常:" + e.getMessage());
        System.out.println("*****************************************");
    }

3. DeptTest——测试方法

package com.test;

import com.dao.DeptDao;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class DeptTest {
	// 声明spring引用
    private static ApplicationContext as = null;

    static {
        as = new ClassPathXmlApplicationContext("applicationContext.xml");
    }

    @Test
    public void testDept() {
        DeptDao deptDao = (DeptDao) as.getBean("deptDao");
        deptDao.insert("开发部");
    }


}

二、最终通知

最终通知:切入点正常执行后,或异常发生后立即执行。一般在前置通知之后,在后置通知和异常通知之前。

1. DmlAspect——切面方法

含义/作用
@After最终通知的注解
execution切入点表达式,用来指定切入点
JoinPoint切入点对象
package com.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.aop.Pointcut;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class DmlAspect {
    // 最终通知的切面方法
    @After("execution(* com.dao.*.*(*))")
    public void doAfter(JoinPoint point) {
        System.out.println("*****************最终通知**********************");
    }
}

2. DeptTest——测试方法

	 @Test
    public void testDept() {
        DeptDao deptDao = (DeptDao) as.getBean("deptDao");
        deptDao.insert("开发部");
    }

三、AOP环绕通知

将前面的前置通知后置通知异常通知最终通知综合以后就形成了环绕通知。切面程序可以调用目标组件的切入点的运行,与struct中的拦截器功能类似。

1. 通知的执行流程

在这里插入图片描述

2. DmlAspect——切面方法

含义/作用
@Around环绕通知的注解
execution切入点表达式,用来指定切入点
ProceedingJoinPoint是JoinPoint的子类,可以控制切入点的执行
proceed()可以调用目标组件,并返回目标组件的返回值
package com.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.aop.Pointcut;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class DmlAspect {
    // 环绕通知
    @Around("execution(* com.dao.*.*(*))")
    public void doAround(ProceedingJoinPoint point) {
        System.out.println("**************前置通知**************");
        System.out.println("拦截切入点的第一个参数:" + point.getArgs()[0]);
        System.out.println("切入点方法原型:" + point.getSignature());
        System.out.println("切入点所属对象:" + point.getTarget());
        System.out.println("**********************************");
        try {
            // 显示反射执行切入点方法
            Object result = point.proceed();
            System.out.println("**************后置通知******************");
            System.out.println("切入点方法的返回值:" + result);
            System.out.println("*********************************");
        } catch (Throwable e) {
            System.out.println("***************异常通知***********************");
            System.out.println("切入点发生的异常:" + e.getMessage());
            System.out.println("*****************************************");
        } finally {
            System.out.println("*****************最终通知**********************");
        }

    }
}

3. 测试和运行结果

在这里插入图片描述

四、切入点表达式

作用:将指定的bean组件下的方法设置为切入点

1. within——按(包名.类名)来匹配主键的

*:是通配符,用来代表全部
并列的两个点:代表子包

1.1 DmlAspect

	// 环绕通知
	// 代表dao包下,所有的子类
    @Around("within(com.dao.*)")
    public void doAround(ProceedingJoinPoint point) {
        System.out.println("**************前置通知**************");
        System.out.println("拦截切入点的第一个参数:" + point.getArgs()[0]);
        System.out.println("切入点方法原型:" + point.getSignature());
        System.out.println("切入点所属对象:" + point.getTarget());
        System.out.println("**********************************");
        try {
            // 显示反射执行切入点方法
            Object result = point.proceed();
            System.out.println("**************后置通知******************");
            System.out.println("切入点方法的返回值:" + result);
            System.out.println("*********************************");
        } catch (Throwable e) {
            System.out.println("***************异常通知***********************");
            System.out.println("切入点发生的异常:" + e.getMessage());
            System.out.println("*****************************************");
        } finally {
            System.out.println("*****************最终通知**********************");
        }
    }

2. bean——按bean组件的id值来匹配

通配符*:写在前面表示以…开头,写在后面表示以…结尾

2.1 DMLAspect

	//表示将所有以...Dao的bean组件都设置为切入点
	@Around("bean(*Dao)")
    public void doAround(ProceedingJoinPoint point) {
        System.out.println("**************前置通知**************");
        System.out.println("拦截切入点的第一个参数:" + point.getArgs()[0]);
        System.out.println("切入点方法原型:" + point.getSignature());
        System.out.println("切入点所属对象:" + point.getTarget());
        System.out.println("**********************************");
        try {
            // 显示反射执行切入点方法
            Object result = point.proceed();
            System.out.println("**************后置通知******************");
            System.out.println("切入点方法的返回值:" + result);
            System.out.println("*********************************");
        } catch (Throwable e) {
            System.out.println("***************异常通知***********************");
            System.out.println("切入点发生的异常:" + e.getMessage());
            System.out.println("*****************************************");
        } finally {
            System.out.println("*****************最终通知**********************");
        }
    }

3. execution——按方法来匹配(常用

在这里插入图片描述

3.1 DmlAspect

	// 返回值类型任意;将com.dao包下的所有类,的insert方法(参数个数和类型任意)设置为切入点
	@Around("execution(* com.dao.*.insert(..))")
    public void doAround(ProceedingJoinPoint point) {
        System.out.println("**************前置通知**************");
        System.out.println("拦截切入点的第一个参数:" + point.getArgs()[0]);
        System.out.println("切入点方法原型:" + point.getSignature());
        System.out.println("切入点所属对象:" + point.getTarget());
        System.out.println("**********************************");
        try {
            // 显示反射执行切入点方法
            Object result = point.proceed();
            System.out.println("**************后置通知******************");
            System.out.println("切入点方法的返回值:" + result);
            System.out.println("*********************************");
        } catch (Throwable e) {
            System.out.println("***************异常通知***********************");
            System.out.println("切入点发生的异常:" + e.getMessage());
            System.out.println("*****************************************");
        } finally {
            System.out.println("*****************最终通知**********************");
        }
    }

第三部分:事务控制


一、面向接口编程

spring项目的架构是面向接口编程。

1. 接口

在Java编程语言中,接口是一个抽象类型,是抽象方法的集合,用interface来声明。一个类通过继承接口的方式,从而来继承接口里的抽象方法。

2. 面向接口编程

在系统分析或架构设计中,每个层级的程序并不是直接提供程序服务,而是定义一组接口,通过实现接口来提供功能。面向接口编程实际上是面向对象编程的一部分。

3. 面向接口编程的优点

在这里插入图片描述

二、spring和mybatis整合

除了实体类不创建为bean组件,其它都要设置为bean组件。mapper通过配置文件将其设置为bean组件;service的实现类通过@Service注解将其设置为bean组件。

1. 新建文件,引入jar包

这里创建的是JavaSE项目。本地数据库是5版本的就引入5版本的jar包;8版本的就引入8版本的jar包,并设置配置文件中有关数据库的内容。
在这里插入图片描述

2. 添加配置文件

添加到src路径下

mybatis.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!--添加自定义的类型转换器-->
   <typeHandlers>
       <typeHandler handler="com.tentact.common.StringArrayTypeHandler" javaType="[Ljava.lang.String;" jdbcType="VARCHAR"></typeHandler>
   </typeHandlers>
    
</configuration>

applicationContext.xml

①添加c3p0数据源,用来连接数据库和将数据库的数据源new成对象
②创建持久层核心处理类对象,用来操作数据库
③将数据访问层的类转为bean组件
④将指定包下的组件都添加到spring容器中

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd">
	<!--设置c3p0数据源,数据源有缓存和连接池,用来维护和数据库的连接将数据库的数据源new成对象-->
	<bean class="com.mchange.v2.c3p0.ComboPooledDataSource" id="dataSource">
		<property name="jdbcUrl"
			value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&amp;characterEncoding=utf-8" />
		<property name="driverClass" value="com.mysql.cj.jdbc.Driver" />
		<property name="user" value="root" />
		<property name="password" value="123456" />
		<property name="initialPoolSize" value="3" />
		<property name="maxPoolSize" value="10" />
		<property name="minPoolSize" value="1" />
		<property name="acquireIncrement" value="3" />
		<property name="maxIdleTime" value="60" />
	</bean>
	<!-- 配置sqlSessionFactory,指定mybatis的映射文件 -->
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<property name="configLocation" value="classpath:mybatis.xml" />
		<property name="mapperLocations" value="classpath:com/tentact/mapping/*.xml"></property>
	</bean>

	<!-- 自动扫描数据访问层,将数据访问层的类转成bean组件 -->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<!-- 扫描产生mapper接口文件 -->
		<property name="basePackage" value="com.tentact.mapper"></property>
		<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
	</bean>
	<!-- 开启自动扫描,通过扫描包下的bean组件,将组件自动注入到spring容器中 -->
	<context:component-scan base-package="com.tentact"></context:component-scan>
</beans>

bean、mapper、mapping文件用代码生成器自动生成

StudentService

package com.tentact.service;

import com.tentact.bean.Student;


public interface StudentService {
    int deleteByPrimaryKey(Integer id);

    int insert(Student record);

    int insertSelective(Student record);

    Student selectByPrimaryKey(Integer id);

    int updateByPrimaryKeySelective(Student record);

    int updateByPrimaryKey(Student record);
}

StudentServiceImpl

package com.tentact.service;

import com.tentact.bean.Student;
import com.tentact.mapper.StudentMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

// 将接口类变为bean对象
@Service
public class StudentServiceImpl implements StudentService{
	// 自动获取StudentMapper的bean对象
    @Autowired
    private StudentMapper studentMapper;

    @Override
    public int deleteByPrimaryKey(Integer id) {
        return 0;
    }

    @Override
    public int insert(Student record) {
        return 0;
    }

    @Override
    public int insertSelective(Student record) {
        return 0;
    }

	// 这里用设个方法进行测试
    @Override
    public Student selectByPrimaryKey(Integer id) {
        return this.studentMapper.selectByPrimaryKey(id);
    }

    @Override
    public int updateByPrimaryKeySelective(Student record) {
        return 0;
    }

    @Override
    public int updateByPrimaryKey(Student record) {
        return 0;
    }
}

StudentTest

package com.tentact.test;

import com.tentact.bean.Student;
import com.tentact.service.StudentService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;


public class StudentTest {
    // 创建spring对象
    private static ApplicationContext ac = null;
    static {
        ac  = new ClassPathXmlApplicationContext("applicationContext.xml");
    }

    @Test
    public void selectByPrimaryKey() {
        StudentService studentService = (StudentService) ac.getBean("studentServiceImpl");
        Student student = studentService.selectByPrimaryKey(1);
        if (student != null) {
            System.out.println(student.getId() + "\t" + student.getName());
        }
    }

}


总结

今天学了面向切面编程的异常通知、最终通知和环绕通知。了解了什么是面向切面编程。具体应用等以后遇到再补充吧!下午主要是将spring和mybatis框架进行了一下整合。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

程序员_动次动次

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

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

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

打赏作者

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

抵扣说明:

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

余额充值