Aspectj进行切面实现aop—他是一个专门做出来进行注解方式开发的。
AspectJ是一个面向切面的框架,它扩展了Java语言。AspectJ定义了AOP语法,它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件。
通过aspectj来进行注解式的开发。
例子—有一个猴子, 还有一个果园,在这个果园中有一个管理员; 当猴子不来偷东西的时候,就不会抓他,当猴子走到果园偷桃子时就会触发通知,管理员知道有猴子偷东西。
1.在pom文件中加入aspectj的注解
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.1</version>
</dependency>
2.写主要的类
//主流业务类
public class Monkey {
public void stealPeaches(String name) {
System.out.println("我是猴子,我要去偷桃子,我叫"+name);
}
}
3.写切面
//切面 猴子跑过来偷桃就会触发事件
//加入aspect这个注解就是一个切面
@Aspect
public class Guardian {
//切入点 当猴子不偷桃时就不会切入进去,一偷桃就切入
@Pointcut("execution(* com.zll.aop.Monkey.stealPeaches(..))")
public void foundMonkey() {
}
//前置通知
@Before(value = "foundMonkey()")
public void foundBefore() {
System.out.println("等猴子偷桃时就抓住它");
}
@AfterReturning(value = "foundMonkey() && args(name,..)")
public void foundAfter(String name) {
System.out.println("猴子偷桃被抓住了,他叫"+name);
}
}
4.在xml文件中配置
<?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"
xmlns:context="http://www.springframework.org/schema/context" 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-2.0.xsd">
<bean id="monkey" class="com.zll.aop.Monkey"></bean>
<bean id="guardian" class="com.zll.aop.Guardian"></bean>
<!-- 支持aspectj -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
这个地方可以通过xml文件注入,也可以通过注解注入
5.测试
public class Test {
public static void main(String[] args) {
ApplicationContext app=new ClassPathXmlApplicationContext("bean.xml");
Monkey monkey=app.getBean("monkey", Monkey.class);
monkey.stealPeaches("孙悟空");
}
}
注解方式写日志
接口
public interface UserService {
void addUser();
void delUser();
void updateUser();
void find();
}
业务
@Component
public class UserServiceImpl implements UserService{
public void addUser() {
System.out.println("-----用户被添加-----");
}
public void delUser() {
System.out.println("-----用户被删除-----");
}
public void updateUser() {
//int a=10/0;
System.out.println("-----用户被更新-----");
}
public void find() {
System.out.println("-----用户被查找-----");
}
}
切面
@Component
@Aspect
public class LogAdvice {
//前置通知 括号内是约束条件 对方法名字内带 User起作用
@Before("execution(void *User(..))")
public void before(JoinPoint jp) {
//切入点,获取目标对象名称
String name=jp.getSignature().getName();
System.out.println("-----前置通知启动------目标对象业务名称:"+name);
}
//后置通知
@After("execution(void *User(..))")
public void After(JoinPoint jp) {
String name=jp.getSignature().getName();
System.out.println("-----后置通知启动------目标对象业务名称:"+name);
}
//环绕通知
@Around("execution(void *find(..))")
public void Around(ProceedingJoinPoint pj) throws Throwable {
String name=pj.getSignature().getName();
System.out.println("-----环绕通知启动------目标对象业务名称:"+name);
pj.proceed();
System.out.println("-----环绕通知结束------目标对象业务名称:"+name);
}
@AfterReturning("execution(void *User(..))")
public void final01(JoinPoint jp) {
String name=jp.getSignature().getName();
System.out.println("-----最终通知执行------目标对象业务名称:"+name);
}
//异常通知
@AfterThrowing("execution(void *User(..))")
public void execption(JoinPoint jp) {
String name=jp.getSignature().getName();
System.out.println("-----执行出现异常-----"+name+"里面存在异常");
}
}
测试
public class Test {
public static void main(String[] args) {
ApplicationContext app=new ClassPathXmlApplicationContext("bean.xml");
UserService userService=app.getBean("userServiceImpl",UserService.class);
userService.addUser();
userService.delUser();
userService.updateUser();
userService.find();
}
}
xml文件
<!--自动扫描我们的包 -->
<context:component-scan base-package="com.zll.aop"></context:component-scan>
<!--开启注解方式来实现aop 自动代理-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
Spring常用的一个aop的例子就是事务管理, 增删改操作,都会需要事务管理, 就需要我们配置一个切面, 当你的这三个方法走到切面的时候, 进行事务操作。
Spring中七种Propagation类的事务属性详解:
REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。
MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。
REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。
NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
NESTED:支持当前事务,如果当前事务存在,则执行一个嵌套事务,如果当前没有事务,就新建一个事务。
使用xml文件进行事务的操作很麻烦。