Spring AOP 的底层是通过JDK动态代理或CGLib动态代理技术,为目标Bean执行横向织入。JDK动态代理主要针对于接口类,而不属于接口类的则需要使用CGLib生成目标对象的子类。
由于JDK动态代理或是CGLib动态代理都是针对目标类生成的子类,所以需要增强的方法不能使用final修饰。
示例:
JDK动态代理
创建一个接口和实现类用于测试:
package com.spring.aop.dao;
public interface UserDao {
void save();
void update();
void delete();
void select();
}
package com.spring.aop.dao.impl;
import com.spring.aop.dao.UserDao;
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("保存操作....");
}
@Override
public void update() {
System.out.println("更新操作....");
}
@Override
public void delete() {
System.out.println("删除操作....");
}
@Override
public void select() {
System.out.println("查询操作....");
}
}
创建JDK动态代理类
package com.spring.aop;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class MyJdkProxy implements InvocationHandler {
private Object o;
public MyJdkProxy(Object o) {
this.o = o;
}
public Object createProxy() {
return Proxy.newProxyInstance(o.getClass().getClassLoader(), o.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("save".equals(method.getName())) {
System.out.println("==========权限校验=========");
}
return method.invoke(o, args);
}
}
JDK动态代理是Java的实现方式,是一个实现在创建类时在运行时指定的接口列表的类,该类具有下面描述的行为。代理接口是代理类实现的一个接口。代理实例是代理类的一个实例。每个代理实例都有一个关联的调用处理程序对象,它可以实现接口InvocationHandler
。通过其中一个代理接口的代理实例上的方法调用将被指派到实例的调用处理程序的 Invoke 方法,并传递代理实例、识别调用方法的 java.lang.reflect.Method
对象以及包含参数的 Object 类型的数组。调用处理程序以适当的方式处理编码的方法调用,并且它返回的结果将作为代理实例上方法调用的结果返回。
调用Proxy
的静态方法newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
就可以创建一个接口的代理类。方法中的第一个参数是类的加载器,第二个参数为类的接口列表,第三个参数为代理实例的调用处理程序实现的接口,该接口需要实现invoke()
方法,此处可以选择使用匿名内部类或者使用继承InvocationHandler
。
测试类:
package com.spring.aop;
import com.spring.aop.dao.UserDao;
import com.spring.aop.dao.impl.UserDaoImpl;
import org.junit.Test;
public class TestAop {
@Test
public void test1() {
UserDao userDao = new UserDaoImpl();
UserDao proxy = (UserDao) new MyJdkProxy(userDao).createProxy();
proxy.save();
}
}
可以查看测试结果
CGLib动态代理
创建一个不实现接口的业务类
package com.spring.aop.dao;
public class ProductDao {
public void save() {
System.out.println("保存操作....");
}
public void update() {
System.out.println("更新操作....");
}
public void delete() {
System.out.println("删除操作....");
}
public void select() {
System.out.println("查询操作....");
}
}
使用CGLib代理时,要先导入Spring所需jar包。创建CGLib动态代理类:
package com.spring.aop;
import com.spring.aop.dao.ProductDao;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class MyCglibProxy implements MethodInterceptor {
private Object o;
public MyCglibProxy(Object o) {
this.o = o;
}
public Object createProxy() {
// 1. 创建CGLib核心类
Enhancer enhancer = new Enhancer();
// 2. 设置父类
enhancer.setSuperclass(o.getClass());
// 3. 设置回调
enhancer.setCallback(this);
// 4. 创建代理类
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
if ("update".equals(method.getName())) {
System.out.println("==============权限校验===============");
}
return methodProxy.invokeSuper(o, objects);
}
}
测试类:
package com.spring.aop;
import com.spring.aop.dao.ProductDao;
import com.spring.aop.dao.UserDao;
import com.spring.aop.dao.impl.UserDaoImpl;
import org.junit.Test;
public class TestAop {
@Test
public void test2() {
ProductDao productDao = new ProductDao();
ProductDao proxy = (ProductDao) new MyCglibProxy(productDao).createProxy();
proxy.update();
}
}