1 原理
JDK动态代理
- 通过 java.lang.reflect.Proxy类 的 newProxyInstance方法 创建代理类。
- newProxyInstance方法:

1. 参数一:类加载器
1. 参数二:所增强方法所在的类,这个类实现的接口,支持多个接口
1. 参数三:实现InvocationHandle接口,重写invoke方法来添加新的功能
接口:
1 2 3 4
| public interface UserDao { public int add(int a, int b); public int multi(int a, int b); }
|
实现类:
1 2 3 4 5 6 7 8 9 10 11
| public class UserDaoImpl implements UserDao { @Override public int add(int a, int b) { return a+b; }
@Override public int multi(int a, int b) { return a*b; } }
|
增强类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class UserDaoProxy implements InvocationHandler { Object obj; public UserDaoProxy(Object obj){ this.obj = obj; }
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("进入" + method.getName() + "方法,这是新增的代码,参数有" + Arrays.toString(args));
Object invoke = method.invoke(obj, args);
System.out.println("方法原先的内容执行完了");
return invoke; } }
|
测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class Main {
@Test public void test1(){
Class[] interfaces = {UserDao.class}; UserDao userDao = new UserDaoImpl(); UserDao userDaoProxy = (UserDao) Proxy.newProxyInstance(Main.class.getClassLoader(), interfaces, new UserDaoProxy(userDao)); int result = userDaoProxy.add(1, 2); System.out.println(result); } }
|

CGLIB动态代理
目标类
1 2 3 4 5
| public class TargetClass { public void doSomething() { System.out.println("目标方法"); } }
|
实现MethodInterceptor接口
1 2 3 4 5 6 7 8 9 10 11 12 13
| import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method;
public class CustomMethodInterceptor implements MethodInterceptor { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("执行目标方法之前"); Object result = proxy.invokeSuper(obj, args); System.out.println("执行目标方法之后"); return result; } }
|
测试
1 2 3 4 5 6 7 8 9 10 11 12
| import net.sf.cglib.proxy.Enhancer;
public class CglibDynamicProxyDemo { public static void main(String[] args) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(TargetClass.class); enhancer.setCallback(new CustomMethodInterceptor());
TargetClass proxy = (TargetClass) enhancer.create(); proxy.doSomething(); } }
|
结果
2 基于AspectJ实现AOP操作
AOP相关术语
- 连接点:类中可以被增强的方法,称为连接点。
- 切入点:实际被增强的方法,称为切入点。
- 通知:增强的那一部分逻辑代码。通知有多种类型:
- 前置通知:增强部分代码在原代码前面。
- 后置通知:增强部分代码在原代码后面。
- 环绕通知:增强部分代码既有在原代码前面,也有在原代码后面。
- 异常通知:原代码发生异常后才会执行。
- 最终通知:类似与finally那一部分
- 切面:指把通知应用到切入点这一个动作。
切入点表达式
语法:execution([权限修饰符] [返回类型] [类全路径] [方法名称] [参数列表])
对 com.atguigu.dao.BookDao 类里面的 add 进行增强
1
| execution(* com.auguigu.dao.BookDao.add(..))
|
对 com.atguigu.dao.BookDao 类里面的所有的方法进行增强
1
| execution(* com.atguigu.dao.BookDao.*(..))
|
对 com.atguigu.dao 包里面所有类,类里面所有方法进行增强
1
| execution(* com.atguigu.dao.*.* (..))
|
基于注解实现AOP
1 2 3 4 5 6
| @Component public class User { public void add(){ System.out.println("User.add()"); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| @Component @Aspect public class UserProxy { @Before(value="execution(* com.oymn.spring5.User.add(..))") public void before(){ System.out.println("UserProxy.before()"); } @AfterReturning(value="execution(* com.oymn.spring5.User.add(..))") public void afterReturning(){ System.out.println("UserProxy.afterReturning()"); } @After(value="execution(* com.oymn.spring5.User.add(..))") public void After(){ System.out.println("UserProxy.After()"); }
@AfterThrowing(value="execution(* com.oymn.spring5.User.add(..))") public void AfterThrowing(){ System.out.println("UserProxy.AfterThrowing()"); }
@Around(value="execution(* com.oymn.spring5.User.add(..))") public void Around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
System.out.println("UserProxy.Around() _1");
proceedingJoinPoint.proceed();
System.out.println("UserProxy.Around() _2"); } }
|
配置类
1 2 3 4 5 6
| @Configuration @ComponentScan(basePackages = "com.oymn.spring5") @EnableAspectJAutoProxy(proxyTargetClass = true) public class Config { }
|
测试
1 2 3 4 5 6
| @Test public void test2(){ ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml"); User user = context.getBean("user", User.class); user.add(); }
|
输出

异常
1 2 3 4
| public void add(){ int i = 1/0; System.out.println("User.add()"); }
|

对于上面的例子,有很多通知的切入点都是相同的方法,因此,可以将该切入点进行抽取:通过@Pointcut注解
1 2 3 4 5 6 7 8 9 10
| @Pointcut(value="execution(* com.oymn.spring5.User.add(..))") public void pointDemo(){ }
@Before(value="pointDemo()") public void before(){ System.out.println("UserProxy.before()"); }
|
优先级
当有多个增强类对同一方法进行增强时,可以通过**@Order(数字值)来设置增强类的优先级,数字越小优先级越高。**
1 2 3 4
| @Component @Aspect @Order(1) public class PersonProxy
|