Spring AOP
AOP作为Spring中一个核心模块,通过代理模式在程序中架起了一层可自定义的拦截器
代理模式原理
-
静态代理
一个静态代理只能代理一个接口下的所有实现类
代码
/**
* 一个静态代理只能代理一个接口下的所有实现类
*/
public class GreetingProxyStatic implements Greeting{
private GreetingImpl greetingImpl;
public GreetingProxyStatic(GreetingImpl greetingImpl) {
super();
this.greetingImpl = greetingImpl;
}
@Override
public void sayHello(String name) {
before();
greetingImpl.sayHello(name);
after();
}
private void before() {
System.out.println("before");
}
private void after() {
System.out.println("before");
}
}
class GreetingImpl implements Greeting{
@Override
public void sayHello(String name) {
System.out.println("name");
}
}
interface Greeting {
void sayHello(String name);
}
class Client {
public static void main(String[] args) {
Greeting greetingProxyStatic = new GreetingProxyStatic(new GreetingImpl());
greetingProxyStatic.sayHello("name");
}
}
-
动态代理
一个动态代理可代理多个接口下的实现类,可通过配置proxy-target-class(false为JDK,true为CGlib)去切换- jdk代理
jdk代理是Spring的默认选择,必须依赖接口
代码
- jdk代理
package com.td.mode;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 被代理的Class必须实现接口
* spring默认使用JDK动态代理
*/
public class GreetingProxyDynamicJDK implements InvocationHandler{
private Object target;
public GreetingProxyDynamicJDK(Object target) {
super();
this.target = target;
}
@SuppressWarnings("unchecked")
public <T> T getProxy() {
return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object result = method.invoke(target, args);
after();
return result;
}
private void before() {
System.out.println("before");
}
private void after() {
System.out.println("before");
}
}
class GreetingImpl implements Greeting{
@Override
public void sayHello(String name) {
System.out.println("name");
}
}
interface Greeting {
void sayHello(String name);
}
class Client {
public static void main(String[] args) {
Greeting greetingProxyDynamicJDK = new GreetingProxyDynamicJDK(new GreetingImpl()).getProxy();
greetingProxyDynamicJDK.sayHello("name");
}
}
- cglib代理
jdk代理是Spring的默认选择,可直接代理任何类
代码
import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
/**
* 直接代理Class,被代理的Class不需要实现接口
* spring-boot默认使用CGlib动态代理
*/
public class GreetingProxyDynamicCGlib implements MethodInterceptor{
public static final GreetingProxyDynamicCGlib instance = new GreetingProxyDynamicCGlib();
private GreetingProxyDynamicCGlib() {}
@SuppressWarnings("unchecked")
public <T> T getProxy(Class<T> cls) {
return (T) Enhancer.create(cls, this);
}
@Override
public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy) throws Throwable {
before();
Object result = proxy.invokeSuper(target, args);
after();
return result;
}
private void before() {
System.out.println("before");
}
private void after() {
System.out.println("before");
}
}
class GreetingImpl implements Greeting{
@Override
public void sayHello(String name) {
System.out.println("name");
}
}
interface Greeting {
void sayHello(String name);
}
class Client {
public static void main(String[] args) {
Greeting greetingProxyDynamicCGlib = GreetingProxyDynamicCGlib.instance.getProxy(GreetingImpl.class);
greetingProxyDynamicCGlib.sayHello("name");
}
}
Spring AOP使用
直接上代码,笔者为了简单易读只写个Demo,读者可对其进一步封装,
- 扫描配置类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import com.zgg.group2.rest.aspect.pojo.AspectDemo;
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass=false)
@ComponentScan(basePackages="com.zgg.group2")
public class AspectConfig {
@Bean
public AspectDemo aspectDemo() {
return new AspectDemo();
}
}
- 拦截器
import org.aspectj.lang.ProceedingJoinPoint;
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.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import com.zgg.group2.rest.bean.ZgUser;
@Aspect
@Component
public class AspectDemo {
//execution(任意返回值 url.任意类名(任意方法名))
// @execution(* com.zgg.group2.rest.impl.*.save*(..))
@Pointcut("execution(* com.zgg.group2.rest.impl.*.*(com.zgg.group2.rest.bean.ZgUser)) "
+ "&& args(zgUser)")
public void pointcutProxy(ZgUser zgUser){};
@Before("pointcutProxy(zgUser)")
public void before1(ZgUser zgUser) {
System.out.println("execute method before1 and name = "+zgUser.getName());
}
@Before("pointcutProxy(zgUser)")
public void before2(ZgUser zgUser) {
System.out.println("execute method before2 and name = "+zgUser.getName());
}
@AfterReturning("pointcutProxy(zgUser)")
public void afterReturning(ZgUser zgUser) {
System.out.println("execute method afterReturning and name = "+zgUser.getName());
}
@AfterThrowing("pointcutProxy(zgUser)")
public void afterThrowing(ZgUser zgUser) {
System.out.println("execute method afterThrowing and name = "+zgUser.getName());
}
@Around("pointcutProxy(zgUser)")
public void around(ProceedingJoinPoint jp, ZgUser zgUser) {
try {
System.out.println("around before and name = "+zgUser.getName());
jp.proceed();
System.out.println("around after");
} catch (Throwable e) {
e.printStackTrace();
}
}
}