设计模式之动态代理模式实战

昨天分享了静态代理的概念及存在的缺点,所以今天讲的动态代理模式十分重要。动态代理在我们工作当中应用相当广泛,如Srping AOP就是动态代理的在开源框架的比较出名的应用。

动态代理有两种试,一是通过JDK自带的API实现动态代理,二是通过别的字节码框架实现,如cglib。

需要注意的是JDK只能针对接口实现动态代理,不能代理普通类,使用具有局限性。而cglib可以代理接口及所有的普通类。

下面拿昨天保存用户信息的例子继续用动态代理来实现。

用户接口

public interfaceUserInterface{

boolean saveUser(User user);

}

用户接口实现

public classUserInterfaceImplimplements UserInterface {

@Override

public boolean saveUser(User user) {

System.out.println("保存用户: " + user.getName());

return true;

}

}

public classTest{

public static void main(String[] args) {

// JDK动态代理

testJDKProxy();

// Cglib接口代理

testCglibInterfaceProxy();

// Cglib类代理

testCglibClassProxy();

}

private static voidtestJDKProxy() {

User user = new User();

user.setName("tom");

UserProxy.getUserProxy().saveUser(user);

}

static class UserProxy {

private static final InvocationHandler USER_HANDLE = new InvocationHandler() {

@Override

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

System.out.println("JDK接口动态代理-开始保存用户");

Object result = method.invoke(new UserInterfaceImpl(), args);

System.out.println("JDK接口动态代理-保存用户结果: " + result);

System.out.println();

return result;

}

};

public static UserInterface getUserProxy() {

UserInterface userInterface = (UserInterface) Proxy.newProxyInstance(UserProxy.class.getClassLoader(),

new Class[] { UserInterface.class }, USER_HANDLE);

return userInterface;

}

}

private static voidtestCglibInterfaceProxy() {

User user = new User();

user.setName("tom");

UserCglibProxy.getUserProxy().saveUser(user);

}

static class UserCglibProxy {

private static final net.sf.cglib.proxy.InvocationHandler USER_HANDLE = new net.sf.cglib.proxy.InvocationHandler() {

@Override

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

System.out.println("Cglib接口动态代理-开始保存用户");

Object result = method.invoke(new UserInterfaceImpl(), args);

System.out.println("Cglib接口动态代理-保存用户结果: " + result);

System.out.println();

return result;

}

};

public static UserInterface getUserProxy() {

UserInterface userInterface = (UserInterface) net.sf.cglib.proxy.Proxy.newProxyInstance(

UserCglibProxy.class.getClassLoader(), new Class[] { UserInterface.class }, USER_HANDLE);

return userInterface;

}

}

private static voidtestCglibClassProxy() {

User user = new User();

user.setName("tom");

UserInterfaceImpl userImpl = (UserInterfaceImpl) ClassCgLibProxy.getUserProxy(new UserInterfaceImpl());

userImpl.saveUser(user);

}

static class ClassCgLibProxy {

private static final MethodInterceptor USER_HANDLE = new MethodInterceptor() {

@Override

public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {

System.out.println("Cglib类动态代理-开始保存用户");

Object result = proxy.invokeSuper(obj, args);

System.out.println("Cglib类动态代理-保存用户结果: " + result);

System.out.println();

return result;

}

};

public static Object getUserProxy(Object target) {

Enhancer enhancer = new Enhancer();

enhancer.setSuperclass(target.getClass());

enhancer.setCallback(USER_HANDLE);

return enhancer.create();

}

}

}

结果输出:

JDK接口动态代理-开始保存用户

保存用户: tom

JDK接口动态代理-保存用户结果: true

Cglib接口动态代理-开始保存用户

保存用户: tom

Cglib接口动态代理-保存用户结果: true

Cglib类动态代理-开始保存用户

保存用户: tom

Cglib类动态代理-保存用户结果: true

从例子看出,使用也并不复杂,动态代理与静态代理最主要的区别在于,静态代理是编译期间就确定好的代理关系,而动态代理是运行期间由JVM通过反射等技术生成的代理对象,不存在class文件,代理类与被代理类之间的关系是继承关系,所以,普通类final的方法是不能被动态代理的。

上一篇:Visual Studio 2013编辑HTML文件无设计视图的解决方案


下一篇:lzg_ad: WinXP及Win2003下文件内容搜索不到的解决方案