动态代理就是,在程序运行期,创建目标对象的代理对象,并对目标对象中的方法进行功能性增强的一种技术。
一 Cglib
Cglib是一个开源项目,它的底层是字节码处理框架ASM,提供了比jdk更为强大的动态代理。相比于jdk动态代理的优势有:
- jdk动态代理只能基于接口,代理对象只能是接口类型,而Cglib通过生成子类来实现的,代理对象既可以是实现类,又可以是接口。
- Cglib速度比jdk动态代理更快,性能更好。
Spring对Cglib做了封装,提供了spring-cglib-repack.jar包。
            
            
              java
              
              
            
          
          public class UserService {
    public void test() {
        System.out.println("执行UserService.test");
    }
            
            
              java
              
              
            
          
          import com.xiakexing.service.UserService;
import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
public class UserServiceProxy {
    public static void main(String[] args) {
        UserService target = new UserService();
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(UserService.class);
        // 定义代理逻辑
        enhancer.setCallbacks(new Callback[]{new MethodInterceptor() {
            @Override
            public Object intercept(Object proxy, Method method, Object[] params, MethodProxy
                                    methodProxy) throws Throwable {
                System.out.println("before...");
                Object result = methodProxy.invoke(target, params);
                System.out.println("after...");
                return result;
            }
        }});
        // 创建代理对象
        UserService userService = (UserService) enhancer.create();
        userService.test();
    }
}二 JDK动态代理
大家或多或少都有了解,此处不在赘述。
三 ProxyFactory类
对上述两种代理实现,Spring进行了封装,统一为ProxyFactory,表示创建代理对象的一个工厂。
我们不用关心底层使用了cglib还是JDK动态代理,ProxyFactory会自动判断:
- 如果被代理类实现了接口,就会用jdk动态代理;
- 如果没有实现接口,就会用cglib技术。
3.1 使用Cglib
            
            
              java
              
              
            
          
          package com.xiakexing.aop;
import com.xiakexing.service.UserService;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.framework.ProxyFactory;
public class ProxyFactoryTest {
    public static void main(String[] args) {
        UserService target = new UserService();
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setTarget(target);
        proxyFactory.addAdvice(new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
                System.out.println("before...");
                Object result = invocation.proceed();
                System.out.println("after...");
                return result;
            }
        });
        UserService userService = (UserService) proxyFactory.getProxy();
        userService.test();
    }
}上面示例中,没有给UserService指定接口实现, 因此使用了Cglib代理。
3.2 使用JDK代理
定义OrderInterface接口,提供实现类OrderService。
            
            
              java
              
              
            
          
          public interface OrderInterface {
    void test();
}
            
            
              java
              
              
            
          
          public class OrderService implements OrderInterface {
    public void test() {
        System.out.println("执行OrderService.test");
    }
}
            
            
              java
              
              
            
          
          package com.xiakexing.aop;
import com.xiakexing.service.OrderInterface;
import com.xiakexing.service.OrderService;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.framework.ProxyFactory;
public class ProxyFactoryTest {
    public static void main(String[] args) {
        OrderInterface target = new OrderService();
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setTarget(target);
        // 添加要实现的接口
        proxyFactory.addInterface(OrderInterface.class);
        proxyFactory.addAdvice(new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
                System.out.println("before...");
                Object result = invocation.proceed();
                System.out.println("after...");
                return result;
            }
        });
        OrderInterface orderService = (OrderInterface) proxyFactory.getProxy();
        System.out.println(orderService.getClass().getName());
        orderService.test();
    }
}当主动指定代理对象要实现OrderInterface接口时,将使用JDK动态代理。
四 ProxyFactoryBean类
我们希望能够从Spring容器中,直接获取ProxyFactory所创建的代理对象,就要使用ProxyFactoryBean。
该类实现了FactoryBean接口,用于创建Proxy对象,需要提供被代理类和代理逻辑,getObject()会返回代理类Bean对象。
            
            
              java
              
              
            
          
          // 返回UserService的代理对象
@Bean
public ProxyFactoryBean userServiceProxy() {
    UserService userService = new UserService();
    ProxyFactoryBean factoryBean = new ProxyFactoryBean();
    factoryBean.setTarget(userService);
    factoryBean.addAdvice(new MethodInterceptor() {
        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
            System.out.println("before...");
            Object result = invocation.proceed();
            System.out.println("after...");
            return result;
        }
    });
    return factoryBean;
}五 一些概念
5.1 Advice通知
在已有方法的前、后、异常或最终处加入的增加逻辑,包括:
- Before Advice:方法之前执行
- After returning advice:方法return后执行
- After throwing advice:方法抛异常后执行
- After finally advice:方法执行完finally之后执行,在return之后
- Around advice:这是功能最强大的Advice,可以自定义执行顺序
5.2 Pointcut切面点
需要应用Advice的方法范围,指定对哪些类的哪些方法进行增强。
5.3 Advisor接口
一个Advisor由一个Pointcut和一个Advice组成。子类PointcutAdvisor有如下方法。 
如下,创建UserService的代理对象,只对名称为test的方法进行增强。
            
            
              java
              
              
            
          
          UserService target = new UserService();
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(target);
proxyFactory.addAdvisor(new PointcutAdvisor() {
    @Override
    public Pointcut getPointcut() {
        return new StaticMethodMatcherPointcut() {
            @Override
            public boolean matches(Method method, Class<?> targetClass) {
                return method.getName().equals("test");
            }
        };
    }
    @Override
    public Advice getAdvice() {
        return new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
                System.out.println("before...");
                Object result = invocation.proceed();
                System.out.println("after...");
                return result;
            }
        };
    }
    @Override
    public boolean isPerInstance() {
        return false;
    }
});
UserService userService = (UserService) proxyFactory.getProxy();
userService.test();六 使用注解
上面示例中,我们自行指定了要代理的类,自行创建了Advisor对象。Spring中代理肯定不能如此麻烦的实现。
使用注解,将Advice、Pointcut都定义为Bean放入容器中,Spring就具备了动态生成代理对象的能力了。
            
            
              java
              
              
            
          
          import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class SimpleAspect {
    @Before("execution(public void com.xiakexing.service.UserService.test())")
    public void before(JoinPoint joinPoint) {
        System.out.println("Before...");
    }
}OOP表示面向对象编程,AOP表示面向切面编程,都只是一种编程思想。而Spring提供了一套机制,可以让我们更加容易的实现AOP编程,这套机制我们称之为 Spring AOP。
通过注解方式来定义Pointcut和Advice,首创是AspectJ组件。Spring依赖了AspectJ,会去解析相应注解,利用动态代理机制生成代理对象。