基于AspectJ的AOP开发

AspectJ简介

  • 是一个基于Java语言的AOP框架

  • Spring2.0以后新增了对AspectJ切点表达式支持

  • @AspectJ通过JDK5注解技术,允许直接在Bean类中定义切面

  • 需要导入Spring AOP和AspectJ相关jar包

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    <!-- 引入spring基本开发包-->
    <dependencies>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>4.2.4.RELEASE</version>
    </dependency>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>4.2.4.RELEASE</version>
    </dependency>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-beans</artifactId>
    <version>4.2.4.RELEASE</version>
    </dependency>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-expression</artifactId>
    <version>4.2.4.RELEASE</version>
    </dependency>
    <!--加载aspectj的包-->
    <!-- aspectj 基于aop-->
    <dependency>
    <groupId>aopalliance</groupId>
    <artifactId>aopalliance</artifactId>
    <version>1.0</version>
    </dependency>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>4.2.4.RELEASE</version>
    </dependency>
    <dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.8.9</version>
    </dependency>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>4.2.4.RELEASE</version>
    </dependency>
    <!--测试-->
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>4.2.4.RELEASE</version>
    </dependency>
    </dependencies>
  • 创建配置文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <?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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- bean definitions here -->

    <!--开启AspectJ的注解开发,自动代理-->
    <aop:aspectj-autoproxy/>

    </beans>

AspectJ提供的通知类型

  • @Before 前置通知,相当于BeforeAdvice

    可以在方法中传入JoinPoint对象,获得切点信息

    1
    2
    3
    4
    @Before(value="execution(* com.imooc.aspectJ.demo1.ProductDao.save(..))")
    public void before(JoinPoint joinPoint){
    System.out.println("前置通知==================="+joinPoint);
    }
  • @AfterReturning 后置通知,相当于AfterReturningAdvice

    通过returning属性,定义方法返回值作为参数

    1
    2
    3
    4
    @AfterReturning(value="execution(* com.imooc.aspectJ.demo1.ProductDao.update(..))" ,returning = "result")
    public void afterReturning(Object result){
    System.out.println("后置通知========="+result);
    }
  • @Around 环绕通知,相当于MethodInterceptor

    返回值是目标代理方法执行返回值

    通过ProceedingJoinPoint可以调用拦截目标方法执行

    若不调用ProceedingJointPoint的proceed方法,则目标方法会被拦截

    1
    2
    3
    4
    5
    6
    7
    @Around(value = "execution(* com.imooc.aspectJ.demo1.ProductDao.delete(..))")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println("环绕前通知");
    Object obj = joinPoint.proceed(); //执行目标方法
    System.out.println("环绕后通知");
    return obj;
    }
  • @AfterThrowing 异常抛出通知,相当于ThrowAdvice

    通过设置throwing属性,可以设置发生异常对象参数

    1
    2
    3
    4
    @AfterThrowing(value = "execution(* com.imooc.aspectJ.demo1.ProductDao.findOne(..))",throwing = "e")
    public void afterThrowing(Throwable e){
    System.out.println("抛出异常通知"+e.getMessage());
    }
  • @After 最终final通知,不管是否异常,通知都会执行

    1
    2
    3
    4
    @After(value="execution(* com.imooc.aspectJ.demo1.ProductDao.findAll(..))")
    public void after(){
    System.out.println("最终通知==================");
    }

切入点表达式的定义

  • 通过execution函数,可以定义切点的方法切入

    语法:-execution(<访问修饰符>?<返回类型><方法名>(<参数>)<异常>)

入门案例

  • 切面类

    1
    2
    3
    4
    5
    6
    7
    8
    /* 切面类 */
    @Aspect
    public class MyAspectAnno { // 返回类型 方法 传入值
    @Before(value="execution(* com.imooc.aspectJ.demo1.ProductDao.save(..))")
    public void before(){
    System.out.println("前置通知===================");
    }
    }
  • 测试类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:applicationContext.xml")
    public class SpringDemo1 {

    @Resource(name="productDao")
    private ProductDao productDao;

    @Test
    public void demo1(){
    productDao.save();
    productDao.update();
    productDao.delete();
    productDao.findAll();
    productDao.findOne();
    }
    }
  • 配置文件

    1
    2
    3
    4
    5
    <!--目标类-->
    <bean id="productDao" class="com.imooc.aspectJ.demo1.ProductDao"/>

    <!-- 定义切面-->
    <bean class="com.imooc.aspectJ.demo1.MyAspectAnno"/>

切点命名

  • 使用@Pointcut进行定义

  • 切点方法:private void 无参数方法,方法名为切点名

  • 当通知多个切点时,可以使用"||”进行连接

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @Pointcut(value="execution(* com.imooc.aspectJ.demo1.ProductDao.save(..))")
    private void myPointcut1(){

    }

    @Before(value="myPointcut1()")
    public void before(JoinPoint joinPoint){
    System.out.println("前置通知===================" + joinPoint);
    }

AspectJ的xml方式开发AOP-环境搭建

  • 配置文件(以前置通知为例)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <!--xml配置方式完成AOP开发-->
    <!--配置目标类-->
    <bean id="customerDao" class="com.imooc.aspectJ.demo2.CustomerDaoImpl"/>
    <!-- 配置切面类-->
    <bean id="myAspectXml" class="com.imooc.aspectJ.demo2.MyAspectXml"></bean>
    <!--aop相关配置-->
    <aop:config>
    <!--配置切入点-->
    <aop:pointcut id="pointcut1" expression="execution(* com.imooc.aspectJ.demo2.CustomerDao.save(..))"/>
    <!--配置AOP切面-->
    <aop:aspect ref="myAspectXml" >
    <!--配置前置通知-->
    <aop:before method="before" pointcut-ref="pointcut1"/> <!--before为方法名-->
    </aop:aspect>
    </aop:config>
  • myAspectXml类

    1
    2
    3
    4
    //前置通知
    public void before(JoinPoint joinpoint){
    System.out.println("xml方式前置通知"+joinpoint);
    }
  • 测试类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(value="classpath:applicationContext2.xml")
    public class SpringDemo2 {
    @Resource(name="customerDao")
    private CustomerDao customerDao;
    @Test
    public void demo1(){
    customerDao.save();
    customerDao.update();
    customerDao.delete();
    customerDao.findOne();
    customerDao.findAll();
    }
    }

    提示:其他通知可以参考注解方法和xml方法完成,不作过多举例

JDBC的Template

搭建项目

  • Maven

    • Mysql驱动
    • Spring组件(core\beans\context\aop)
    • JDBC Template(jdbc\tx)
  • Spring配置

    • 数据源
    • JDBC Template
  • 配置pom.xml文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    <properties>
    <spring.version>4.0.2.RELEASE</spring.version>
    </properties>
    <dependencies>
    <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.44</version>
    </dependency>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>4.0.2.RELEASE</version>
    </dependency>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>${spring.version}</version>
    </dependency>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-beans</artifactId>
    <version>${spring.version}</version>
    </dependency>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>${spring.version}</version>
    </dependency>
    <!--jdbc template-->
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>${spring.version}</version>
    </dependency>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>${spring.version}</version>
    </dependency>
    </dependencies>
  • 配置spring.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    <?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">

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/selection_course?useUnicode=true&amp;characterEncoding=utf-8"/>
    <property name="username" value="root"/>
    <property name="password" value=""/>
    </bean>

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource"/>
    </bean>

    </beans>

JDBC Template基本使用

  • execute方法

    1
    2
    3
    4
    5
    public void testExecute(){
    ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
    JdbcTemplate jdbcTemplate = (JdbcTemplate)context.getBean("jdbcTemplate");
    jdbcTemplate.execute("create table user1(id int,name varchar(20))");
    }
  • update与batchUpdate方法

    • int update(String sql, Object[] args);
    • int update(String sql, Object… args);
    1
    2
    3
    4
    5
    6
    7
    8
    9
    public void testUpdate(){
    String sql = "insert into student(name,sex) values(?,?)";
    jdbcTemplate.update(sql,new Object[]{"张三","男"});
    }
    // 另一种写法
    public void testUpdate2(){
    String sql = "update student set sex=? where id = ?";
    jdbcTemplate.update(sql,"女",1); //此处没有用数组
    }
    • int[] batchUpdate(String[] sql);
    • int[] batchUpdate(String sql, List<Object[]> args);
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    public void testBatchUpdate(){
    String[] sqls={
    "insert into student(name,sex) values('关于','女')",
    "insert into student(name,sex) values('刘备','男')",
    "update student set sex='男' where id = 1"
    };
    jdbcTemplate.batchUpdate(sqls);
    }
    // 另一种写法
    public void testBatchUpdate2(){
    String sql = "insert into selection(student,course) values(?,?)";
    List<Object[]> list = new ArrayList<Object[]>();
    list.add(new Object[]{3,1001});
    list.add(new Object[]{3,1003});
    jdbcTemplate.batchUpdate(sql,list);
    }
  • query与queryXXX方法

  • call方法

Spring的事务管理

Java事务导引

  • 什么是事务

    • 事务是正确执行一系列的操作,使得数据库从一种状态转换成另一种状态
  • 事务原则是什么(ISO/IEC所制定的ACID原则)

    • 原子性(Atomicity),即不可分割性
    • 一致性(Consistency)
    • 隔离性(Isolation),事务提交前,结果不应该显示给任何其他事务
    • 持久性(Durability),事务提交后结果将永久保存在数据库中
  • Java事务类型

    • JDBC事务:用Connection对象控制,包括手动和自动模式
    • JTA事务:与实现无关的,与协议无关的API
    • 容器事务

Spring事务接口

1
2
3
4
5
6
7
8
9
10
// Spring事务状态接口:
// 通过调用PlatformTransactionManager的getTransaction()
// 获取事务状态实例
public interface TransactionStatus{
boolean isNewTransaction(); // 是否是新的事务
boolean hasSavepoint(); // 是否有恢复点
void setRollbackOnly(); // 设置为只回滚
boolean isRollbackOnly(); // 是否为只回滚
boolean isCompleted(); // 是否已完成
}

Spring事务属性定义

  • 数据读取类型
    • 脏读(事务还没提交,提前读取)
    • 不可重复读(两次读取的数据不一致)
    • 幻读(事务不是独立执行时发生的一种非预期现象)
  • 事务隔离级别
    • 定义了一个事务可能受其他并发事务影响的程度
  • 事务传播行为
    • 当事务方法被另一个事务方法调用时,必须指定事务应该如何传播
  • 事务是否只读
    • 利用数据库“只读”属性,进行特定优化处理
  • 事务超时
    • 是一个计时器,在特定时间内没有执行完毕,则进行回滚而不是等待
  • 事务回滚
    • 默认情况下,事务只有遇到运行期异常才会回滚,遇到检查型异常时不回滚

编程式事务管理

  • 事务管理器(PlatformTransactionManager)方式
    • 核心类:Spring事务管理的三个接口类及JdbcTemplate类
  • 模板事务(TransactionTemplate)的方式
    • 主要工具为JdbcTemplate类