Spring-AOP和事务实践(注解方式

时间:2021-03-08 20:35:49

1、前言

其实注解方式还是挺不错的,起码最大的感受就是,不用每次去配置xml。
由于对这些知识不太了解,只能直接贴链接,你自己去看吧。

1、系统环境

IDE:InterliJ IDEA 2017.1.5
jdk版本:1.8
Maven版本:3.5
Spring版本:4.3.9.RELEASE
Spring MVC版本:4.3.9.RELEASE
Mybatis版本:3.X
数据库:MySQL 5.7 包含user表的sql脚本

项目基于SpringMVCDemoByXml而来
具体请查看最终的项目的分支SpringMVCDemoByXml-aop_transactions分支

2、AOP实践

添加依赖:

        <!-- ********************** Spring aop********************** -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring-framework.version}</version>
</dependency>

<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version></version>
</dependency>

<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.10</version>
</dependency>

在spring-config.xml的beans节点下加入如下:

    <!-- 使AspectJ注解起作用:自动为匹配的类生产代理对象 对应的注解是@EnableAspectJAutoProxy-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

网上教程都是aspectj的方法,所以导包如上,一个是spring-aop、另两个是aspectj的Runtime和weaver(织入),看完AOP的知识点你会发现有织入这个知识点,那么以来有,也不足为奇。

引用文章xml:


Spring-AOP和事务实践(注解方式

你可以想象config节点为根节点,而一个个aspect组成了整个项目的AOP。
根据本配置文件,我们写出如下代码:

package space.xxhui.aop;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Order(1)
@Aspect
@Component
public class TimeHandler {

@Pointcut("execution(* space.xxhui.controller.*.*(..))")
private void addTime(){}


@Before("addTime()")
@After("addTime()")
public void printTime()
{
System.out.println("CurrentTime = " + System.currentTimeMillis());
}
}
package space.xxhui.aop;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Order(2)
@Aspect
@Component
public class LogHandler {

@Pointcut("execution(* space.xxhui.controller.*.*(..))")
private void printLog(){}

@Before("printLog()")
public void LogBefore()
{
System.out.println("Log before method");
}

@After("printLog()")
public void LogAfter()
{
System.out.println("Log after method");
}

}

注意带入的包。同时我们从注解的位置可以知道,一个aspect对应着一个类。@Pointcut、@Befor、@After对应着方法。

3、事务实践

参考文章引用:

@Transactional 可以作用于接口、接口方法、类以及类方法上。当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。

大概知道知道注解的位置了。其中的属性怎么写,你可以ctrl+鼠标左键,进去看看,再看看那篇文章的解释,大概就了解了。

package space.xxhui.service;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import space.xxhui.DAO.UserDao;
import space.xxhui.POJO.User;

import javax.annotation.Resource;
import java.util.List;

@Transactional
@Service
public class UserService{

@Resource
private UserDao userDao;

public int insert(User pojo){
return userDao.insert(pojo);
}

public int insertSelective(User pojo){
return userDao.insertSelective(pojo);
}

public int insertList(List<User> pojos){
return userDao.insertList(pojos);
}

public int update(User pojo){
return userDao.update(pojo);
}

public User checkUser(User user){
return userDao.checkUser(user);
}
}

插件生成的内容,我只加了最后一个方法和和一个@Transactional注解。

为验证内容是否真的加了事务:
写了一个单元测试:

package space.xxhui;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import space.xxhui.POJO.User;
import space.xxhui.service.UserService;

import java.util.logging.Logger;

@RunWith(SpringJUnit4ClassRunner.class)
// 告诉junit spring配置文件 并且最好分开吧,用主文件会因为资源文件报错
@ContextConfiguration({ "classpath:spring/spring-config.xml"})
@WebAppConfiguration("src/main/resources")
public class UserDAOTest3 {

@Autowired
private UserService userService;

private final Logger logger = Logger.getLogger(String.valueOf(getClass()));

@Test
public void TestUserSerivce(){

logger.info("begin........");
User user = new User();
user.setName("Hitvz");
user.setPwd("123456");
User result = userService.checkUser(user);
if(result!=null){
System.out.println(result.toString());
}
logger.info("end........");
}
}

通过增减@Transactional注解来debugger看效果,断点直接设置在UserService的最后一个方法就行了。
未添加@Transactional注解:


Spring-AOP和事务实践(注解方式

添加@Transactional注解:

Spring-AOP和事务实践(注解方式

PS:这个debugger开始到运行真的不是一般的久,我都可以干很多事了。