SpringAOP原理
主要的功能是:日志记录,性能统计,安全控制,事务处理,异常处理等等。
主要的意图是:将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。
jdk动态代理和CGLIB的区别:
jdk动态代理需要接口,基于反射实现
cglib是基于ASM字节码包装的一个类库
接下来我们一起来看一个aop案例:
新建一个maven project,导入如下依赖信息:
<dependencies>
<!-- 引入Spring-AOP等相关Jar -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>3.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>3.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.5.3</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.1_2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.37</version>
</dependency>
</dependencies>
然后新建一个UserService接口
package com.itmayiedu.service;
public interface UserService {
public void add();
}
再写实现类
package com.itmayiedu.service.impl;
import org.springframework.stereotype.Service;
import com.itmayiedu.service.UserService;
@Service
public class UserServiceImpl implements UserService{
public void add() {
System.out.println("开始往数据库中写数据");
}
}
然后还要把spring.xml文件导入
aop:aspectj-autoproxy</aop:aspectj-autoproxy> 的作用是开启aop注解 (也就是说可以使用@before,@after,@around等注解在我们的代码中)
接下来开始写切面类:
package com.itmayiedu.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class AopLog {
// aop 编程里面有几个通知: 前置通知 后置通知 运行通知 异常通知 环绕通知
@Before("execution(* com.itmayiedu.service.UserService.add(..))")
public void before(){
System.out.println("前置通知");
}
// 后置通知 在方法运行后执行
@After("execution(* com.itmayiedu.service.UserService.add(..))")
public void after(){
System.out.println("后置通知");
}
// 运行通知(当调用方法执行完毕之后在执行,但是在后置通知之后执行)
@AfterReturning("execution(* com.itmayiedu.service.UserService.add(..))")
public void afterReturn(){
System.out.println("运行通知");
}
/ /异常通知
@AfterThrowing("execution(* com.itmayiedu.service.UserService.add(..))")
public void afterThrowing(){
System.out.println("异常通知");
}
// 环绕通知 在方法之前和之后处理事情
@Around("execution(* com.itmayiedu.service.UserService.add(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
// 调用方法之前执行
System.out.println("环绕通知开始");
proceedingJoinPoint.proceed();// 代理调用方法 注意点: 如果调用方法抛出溢出不会执行后面代码
// 调用方法之后执行
System.out.println("环绕通知结束");
}
}
最后编写一个测试类Test01来测试aop效果:
package com.itmayiedu.service;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test01 {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
UserService userService = (UserService) applicationContext.getBean("userServiceImpl");
userService.add();
}
}
运行效果如下:(一定要记得几个通知的顺序)