SpringBoot使用AOP(動態代理)
<!--cglib動態代理-->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.12</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>2.1.7.RELEASE</version>
</dependency>
- 目標target(需要被增強的接口)
//目標target
public interface UserService {
void login(String username, String password);
void regist();
void search();
void update();
}
- 接口實現
/**
* @Description
* @Author zhoumm
* @Version V1.0.0
* @Since 1.0
* @Date 2019-08-24
*/
@Service
public class UserServiceImpl implements UserService{
@Override
public void login(String username, String password) {
System.out.println ("登錄");
}
@Override
public void regist() {
System.out.println ("注冊");
}
@Override
public void search() {
System.out.println ("userService search...");
}
@Override
public void update() {
System.out.println ("update...");
}
}
- 代理增強類
/**
* @Description 代理增強類
* @Author
* @Version V1.0.0
* @Since 1.0
* @Date 2019-08-25
*/
@Component
@Aspect //標識為一個切面供容器讀取
public class UserServiceHelper {
@Before("execution(* com.mmz.tkp.controller.aoptest.UserService.s*(..))")
public void before(){
System.out.println ("前置通知。。。");
}
@AfterReturning(value="execution(* com.mmz.tkp.controller.aoptest.UserService.s*(..))")
public void afterReturning(){
System.out.println ("后置通知。。。");
}
@Around("execution(* com.mmz.tkp.controller.aoptest.UserService.s*(..))")
public void around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println ("環繞前。。。");
Object value = pjp.proceed();
System.out.println (value);
System.out.println ("環繞后。。。");
}
@After("execution(* com.mmz.tkp.controller.aoptest.UserService.s*(..))")
public void after(){
System.out.println ("最終通知。。。");
}
@AfterThrowing(value="execution(* *.s*(..))",throwing="ex")
public void afterThrowing(JoinPoint jp,Throwable ex){
System.out.println ("異常拋出通知" + ex);
}
@Pointcut("execution(* com.mmz.tkp.controller.aoptest.UserService.search(..))")
public void mypointcut(){}
@Pointcut("execution(* com.mmz.tkp.controller.aoptest.UserService.update(..))")
public void mypointcut1(){}
//使用@Pointcut來聲明切點,避免在每個通知中定義切點
@Before("mypointcut()||mypointcut1()")
public void before1(){
System.out.println ("前置通知。。。。");
}
}
- JDK動態代理工廠類
/**
* @Description JDK動態代理工廠類
* 在運行期 ,在JVM內部動態生成class字節碼對象(Class對象)
* Jdk動態代理只針對於接口操作
* @Author
* @Version V1.0.0
* @Since 1.0
* @Date 2019-08-24
*/
public class JDKProxyFactory implements InvocationHandler {
//目標對象
private Object target;
public JDKProxyFactory(Object target) {
this.target = target;
}
//使用Proxy創建代理對象
public Object createProxy(){
//目標類的類加載器對象
ClassLoader classLoader = target.getClass().getClassLoader();
//目標類的實現接口的Class[]
Class<?>[] interfaces = target.getClass().getInterfaces();
//當前對象需實現InvocationHandler接口
return Proxy.newProxyInstance(classLoader,interfaces,this);
}
/**
*
* @param proxy 代理對象,一般不用
* @param method 方法對象
* @param args 方法參數
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//在調用目標對象方法前,統一做一些其他操作,即功能增強
System.out.println ("例如:日志操作......");
return method.invoke(target,args);
}
}
- CGLIB動態代理
/**
* @Description CGLIB動態代理
* CGLIB(Code Generation Library)是一個開源項目
* 是一個強大的,高性能,高質量的Code生成類庫,它可以在運行期擴展Java類與實現Java接口。
* CGLIB包的底層是通過使用一個小而快的字節碼處理框架ASM,來轉換字節碼並生成新的類
*
* 可以為沒有實現接口的類去做代理,也可以為實現接口的類去做代理。
*
* spring采用的是哪一種動態機制:
* 如果目標對象,有接口,優先使用jdk動態代理
* 如果目標對象,無接口,使用cglib動態代理。
* @Author zhoumm
* @Version V1.0.0
* @Since 1.0
* @Date 2019-08-24
*/
public class CglibProxyFactory implements MethodInterceptor {
//目標對象
private Object target;
public CglibProxyFactory(Object target) {
this.target = target;
}
//創建代理對象
public Object createProxy(){
//1.創建Enhancer
Enhancer enhancer = new Enhancer();
//2.傳遞目標對象Class
enhancer.setSuperclass(target.getClass());
//3.設置回調操作(相當於InvocationHandler)
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
//在調用目標對象方法前,統一做一些其他操作,即功能增強
System.out.println ("例如:日志操作......");
return method.invoke(target,args);
}
}
- controller 代理測試
@Api(value = "aop", description = "面向切面編程")
@RestController
@RequestMapping("/kpt/aop")
@Slf4j
@Validated
public class AopBackGroundController {
@Autowired
private UserService userService;
@ApiOperation(value = "JDK動態代理測試", httpMethod = "GET")
@RequestMapping(value = "/jdkproxy", method = RequestMethod.GET)
public void testJDKProxy(){
//JDK動態代理
userService.login("zz","123456");
System.out.println ("--------------JDK動態代理------------");
JDKProxyFactory jdkProxyFactory = new JDKProxyFactory(userService);
UserService userServiceProxy = (UserService)jdkProxyFactory.createProxy();
userServiceProxy.login("zz","123456");
}
@ApiOperation(value = "CGLIB動態代理測試", httpMethod = "GET")
@RequestMapping(value = "/cglibproxy", method = RequestMethod.GET)
public void testCGLIBProxy(){
//CGLIB動態代理
userService.regist();
System.out.println ("--------------CGLIB動態代理------------");
CglibProxyFactory cglibProxyFactory = new CglibProxyFactory(userService);
UserService userServiceProxy = (UserService)cglibProxyFactory.createProxy();
userServiceProxy.regist();
}
@ApiOperation(value = "AspectJ代理測試", httpMethod = "GET")
@RequestMapping(value = "/aspectJproxy", method = RequestMethod.GET)
public void testAspectJ(){
//com.mmz.tkp.controller.aoptest.UserServiceHelper
userService.search();
}
@ApiOperation(value = "切點通知測試", httpMethod = "GET")
@RequestMapping(value = "/aspectJproxy", method = RequestMethod.GET)
public void testPointcutAdvice(){
//com.mmz.tkp.controller.aoptest.UserServiceHelper
userService.search();
}
}