java动态代理 cglib之间的关系

什么是aop?

 

aop(Aspect Oriented Programming)面向切面编程。是oop面向对象思想的一种补充和延续。也是Spring框架的一种重要的组件!

 

Spring中Aop代理是由SpringIOC容器负责生成、管理,其依赖关系也是由IOC容器负责处理的。

 

在Spring中,默认情况下是使用java动态代理技术来实现

 

当需要代理的类不是接口类型的时候,Spring会自动切换为CGLIB来进行代理,也可以强制的选择使用CGLIB来进行代理

 

可以看一下SpringAOP的源代码

package org.springframework.aop.framework;

import java.io.Serializable;
import java.lang.reflect.Proxy;

import org.springframework.aop.SpringProxy;


@SuppressWarnings("serial")
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {

    @Override
  //创建Aop代理
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
      //判断配置是否有效,配置中有代理类信息,判断有没有用户自己定义的解析接口
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { Class<?> targetClass = config.getTargetClass(); if (targetClass == null) { throw new AopConfigException("TargetSource cannot determine target class: " + "Either an interface or a target is required for proxy creation."); }
        //如果是接口,或者Proxy的类,返回默认的JDK动态代理对象
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); }
        //配置中有用户自己指定的代理信息,则使用cglib进行代理
return new ObjenesisCglibAopProxy(config); } else { return new JdkDynamicAopProxy(config); } } private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) { Class<?>[] ifcs = config.getProxiedInterfaces(); return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0]))); } }

首先从通过配置信息解析有没有指定的解析方法。

 

如果配置信息中没有的话,就使用默认的JdkDynamicAopProxy()来进行代理

 

好了,现在知道了Spring在什么情况下使用什么代理。下面开始深入了解一下jdk代理和cglib代理吧

 

动态代理是jdk1.5引进的新的技术。动态代理的类位于Java.lang.reflect包下

先举个栗子!

BookStore.java
public interface BookStore {
     public void addBook();  
     public void deleteBook();
}

还有一个实现该接口的实现类

BookStoreImpl.java
package test;

public class BookStoreImpl implements BookStore {

    public void addBook() {
        System.out.println("增加图书方法。。。");
    }

    public void deleteBook() {
        System.out.println("我現在要刪除一個書");

    }

}
BookStoreProxy.java
package test;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class BookStoreProxy implements InvocationHandler {
    private Object target;

    public Object bind(Object target) {
        this.target = target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        Object result = null;

        System.out.println("代理事务开始啦");
        result = method.invoke(target, args);
        System.out.println("代理事务结束啦");
        return result;
    }

}

测试一下

package test;

public class TestProxy {
    public static void main(String[] args) {
        BookStoreProxy proxy = new BookStoreProxy();
        BookStore bs = (BookStore) proxy.bind(new BookStoreImpl());
        bs.addBook();
        System.out.println("-------------------");
        bs.deleteBook();
    }

}

输出结果

代理事务开始啦
增加图书方法。。。
代理事务结束啦
-------------------
代理事务开始啦
我現在要刪除一個書
代理事务结束啦

 

从测试的过程中可以看到,我们没有改变原来的那个BookStore接口和BookStoreImpl实现类。

 

但是实现了方法的注入

 

这就是动态代理了,它的作用有以下几点

  1.Proxy类的代码量可以降下来,不会因为业务的增大而庞大起来

  2.可以实现aop编程,虽然静态代理也可以实现

  3.降低耦合性,通过参数就可以判断真实的类,不需要事先实例化,比较灵活

 

jdk代理很好啊,但是仔细想一下还是有缺陷啊,Proxy类只能代理接口类

 

所以cglib(Code generation Library)就出现了,完美的拓展了proxy的性能,它可以代理接口的和类。碉堡了

 

再举个栗子!

 

action.java

package cglib.test;

public class Action {
    public void playGame(){
        System.out.println("上班玩游戏...");
    }
    public void smoke(){
        System.out.println("上班抽烟...");
    }
}

ActionFactory.java

package cglib.test;

public class ActionFactory {
    public static Action action = new Action();
    
    public static Action getActionInstance(){
        return action;
    }
}

ActionTest.java

package cglib.test;

import org.junit.Before;
import org.junit.Test;

public class ActionTest {

    @Before
    public void setUp() throws Exception {
    }

    @Test
    public void test() {
        Action action = ActionFactory.getActionInstance();
        action.playGame();
        action.smoke();
    }
}

 

好了,运行没有问题。playGame和smoke两个动作可以完成,但是新的需求来了

老板说,只有他能在上班的时候玩游戏!之前的类不能动!

用jdk中的动态代理当然可以实现,但是我们这没有Action的接口。要是使用jdk动态代理的话,我们还需要创建新的接口!老板说了不能动原来的类。

所以我们选用cglib

 

再搞一个

ActionCglibProxy.java
package cglib.test;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class ActionCglibProxy implements MethodInterceptor {

    private String name;

    private Enhancer enhancer = new Enhancer();

    public ActionCglibProxy(String name) {
        super();
        this.name = name;
    }

    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        if ("zhyonk".equals(name)) {
            Object result = proxy.invokeSuper(obj, args);
            return result;
        }
        System.out.println(name + "你不可以抽烟哦");
        return null;
    }
    public Action getAction(){
        enhancer.setSuperclass(Action.class);
        enhancer.setCallback(this);
        return (Action) enhancer.create();
    }
}

 

 

测试一下

    @Test
    public void TestCglibAction() {
        ActionCglibProxy proxy = new ActionCglibProxy("老板");
        Action action = proxy.getAction();
        action.playGame();
        action.smoke();
    }

 

成功代理了,这个过程中没有用到接口。

 

通过Enhancer进行对类的注入。

 

getAction()返回的是原有的被代理类Action的子类

 

暂时就是这样啦!

 

posted @ 2016-12-23 22:46  zhyonk  阅读(1761)  评论(0编辑  收藏  举报