静态代理
按照上面的代理模式的代码实现,其实就是静态代理了。静态意思是代理类Proxy是在代码在编译时就确定了,而不是在代码中动态生成。如下,我们在示例代码中,接口中有两个函数(doAction1及doAction2),对应的实现类:

/**

  • 服务实现类:委托类
    **/
    public class ServiceImpl implements IService {br/>@Override
    public void doAction1() { System.out.println(" do action1 ");}

    @Override
    public void doAction2() { System.out.println(" do action2 ");}
    }
    现在的需求是需要在doAction1方法执行前和执行后输出日志以便于跟踪,然后对doAction2方法的执行时间进行计算,但又不允许使用修改ServiceImpl类,这个时候,通过一个代理类就可以实现。如下:

/**

  • 服务代理类:代理类
    /
    public class ServiceProxy implements IService {
    /

    • 关联实际委托类
      **/
      private ServiceImpl serviceImpl;

    public ServiceProxy(ServiceImpl serviceImpl) {this.serviceImpl = serviceImpl;}

    @Override
    public void doAction1() {
    System.out.println(" proxy log begin ");
    serviceImpl.doAction1();
    System.out.println(" proxy log end ");
    }

    @Override
    public void doAction2() {
    StopWatch stopWatch = new StopWatch();
    stopWatch.start("timeCalculation");

    serviceImpl.doAction2();
    
    stopWatch.stop();
    System.out.println(stopWatch.prettyPrint());

    }
    }
    客户端执行时,只需要使用代理类执行对应的方法即可,如下:

ServiceProxy serviceProxy = new ServiceProxy(new ServiceImpl());
serviceProxy.doAction1();
JAVA反射机制
JAVA的反射技术其实就是在运行状态中,动态获取类的属性和方法,也可以够调用和操作这个类对象的方法和属性,这种功能就叫做反射。使用反射,可以动态生成类对象,而不用像之前的代码(使用new)静态生成。也可以动态地执行类对象的方法。在示例代码中的reflection包及ReflectionTest类展示了如何动态执行某个类对象的方法。如下,定义了某个类及它的方法:

public class ReflectionService {
public void doSomething(){
System.out.println(" logging reflection service");
}
}
使用反射,动态生成这个类对象,并使用invoke来执行doSomething方法。

//加载类
Class refClass = Class.forName("me.mason.demo.proxy.refrection.ReflectionService");
//生成类对象
Object refClassObject = refClass.getConstructor().newInstance();
//调用类对象方法
Method method = refClass.getDeclaredMethod("doSomething");
method.invoke(refClassObject);
从以上代码可知道,只要知道类路径和它定义的方法名,就可以动态来执行这个方法了,这里动态的意思就是不把需要执行的代码写死在代码中(编译时即确定),而是灵活的在运行时才生成。

3.2 JDK动态代理
3.2.1 JDK动态代理

知道了反射机制可以动态执行类对象,就容易理解动态代理了。在JDK中,已默认提供了动态代理的实现,它的关键点也是在于通过反射执行invoke来动态执行方法,主要实现流程如下:

实现InvocationHandler,由它来实现invoke方法,执行代理函数
使用Proxy类根据类的加载器及接口说明,创建代理类,同时关联委托类
使用代理类执行代理函数,则会调用invoke方法,完成代理
在示例代码中JdkLogProxyHandler类是日志输出代理类,代码如下:

/**

  • 日志动态代理类:JDK实现
    **/
    public class JdkLogProxyHandler implements InvocationHandler {
    private Object targetObject;

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    System.out.println(" jdk dynamic proxy log begin ");
    Object result = method.invoke(targetObject, args);
    System.out.println(" jdk dynamic proxy log end ");
    return result;
    }

    /**

    • 根据委托类动态产生代理类
    • @param targetObject 委托类对象
    • @return 代理类
      */
      public Object createPorxy(Object targetObject){
      this.targetObject = targetObject;
      return Proxy.newProxyInstance(targetObject.getClass().getClassLoader()
      ,targetObject.getClass().getInterfaces(),this);
      }
      }
      在客户端使用时,需要产生代理类,对的日志输出,执行如下(执行输出结果与静态代理功能一致):

@Test
void testLogProxy() {
JdkLogProxyHandler logProxyHandler = new JdkLogProxyHandler();
IService proxy = (IService)logProxyHandler.createPorxy(new ServiceImpl());
proxy.doAction1();
System.out.println("############");
proxy.doAction2();
}
CGLIB动态代理
CGLIB(Code Generator Library)是一个强大的、高性能的代码生成库。CGLIB代理主要通过对字节码的操作,为对象引入间接级别,以控制对象的访问。针对上面没有实现接口的类,CGLIB主要是通过继承来完成动态代理的。在使用方法上,主要也是有3个步骤:

实现MethodInterceptor接口,在intercept方法中实现代理内容(如日志输出)
使用Enhancer及委托类生成代理类
使用代理类执行函数,就会动态调用intercept方法的实现
如下所示是使用CGLIB来实现类的动态代理:

/**

  • 日志动态代理:cglib实现
    **/
    public class CglibLogProxyInterceptor implements MethodInterceptor {br/>@Override
    public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
    System.out.println(" cglib dynamic proxy log begin ");
    Object result = methodProxy.invokeSuper(object, args);
    System.out.println(" cglib dynamic proxy log begin ");
    return result;
    }

    /**

    • 动态创建代理
    • @param cls 委托类
    • @return
      */
      public static T createProxy(Class cls) {
      Enhancer enhancer = new Enhancer();
      enhancer.setSuperclass(cls);
      enhancer.setCallback(new CglibLogProxyInterceptor());
      return (T) enhancer.create();
      }
      }
      从上面代码可知道,代理类是通过Enhancer设置委托类为父类(setsuperclass),并把当前的intercept方法作为回调,以此创建代理类,在客户端执行代理时,则会执行回调,从而达到代理效果,客户端执行如下:

@Test
void testLogProxy() {
CglibService proxy = CglibLogProxyInterceptor.createProxy(CglibService.class);
proxy.doAction1();
System.out.println("############");
proxy.doAction2();
}
定义切面、切点与通知

本示例的需求是对service包下所有类的全部函数统一进行日志输出。因此我们定义一个LogAopAspect作为这个日志输出功能的切面(使用注解@Aspect),使用@Pointcut来确定输出点的匹配规则是service这个包下所有类的全部函数。当真正某个函数执行时,通过动态代理执行通知(使用注解@Before、@After,@Around等)。具体的输出动作,也就是在这些通知里。

@Slf4jbr/>@Aspect
@Component
public class LogAopAspect {

/**
 * 切点:对service包中所有方法进行织入
 */
@Pointcut("execution(* me.mason.demo.proxy.springaop.service.*.*(..))")
private void allServiceMethodPointCut() {}

@Before("allServiceMethodPointCut()")
public void before() { log.info(" spring aop before log begin ");}

@AfterReturning("allServiceMethodPointCut()")
public void after() { log.info(" spring aop before log end ");}

/**
 * 环绕通知,需要返回调用结果
 */
@Around("allServiceMethodPointCut()")
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
    log.info(" spring aop around log begin ");
    try { 
        return proceedingJoinPoint.proceed();
    } finally { 
        log.info(" spring aop around log end ");
    }
}

}
深圳网站建设www.sz886.com