老生常谈设计模式之 *

作者:jingxian 时间:2021-06-12 06:15:50 

一、 * 概念

* 分为JDK * 和cglib * 两种方式。

jdk * 是由Java内部的反射机制来实现的,cglib * 底层则是借助asm来实现的。

总的来说,反射机制在生成类的过程中比较高效,而asm在生成类之后的相关执行过程中比较高效(可以通过将asm生成的类进行缓存,这样解决asm生成类过程低效问题)。

还有一点必须注意:jdk * 的应用前提,必须是目标类基于统一的接口。如果没有上述前提,jdk * 不能应用。

由此可以看出,jdk * 有一定的局限性,cglib这种第三方类库实现的 * 应用更加广泛,且在效率上更有优势。

二、JDK *

以下代码使用代理模式实现一个大小写字符转换的功能。

定义接口和实现类:

ISomeService接口:


package com.ietree.basicskill.designpattern.dynamicproxy.jdk;

/**
* 接口类
*
* @author Root
*/
public interface ISomeService {

String doFirst();

void doSecond();
}

SomeServiceImpl实现类:


package com.ietree.basicskill.designpattern.dynamicproxy.jdk;

/**
* 实现类
*
* @author Root
*/
public class SomeServiceImpl implements ISomeService {

@Override
 public String doFirst() {
   System.out.println("执行doFirst()...");
   String result = "abcde";
   return result;
 }

@Override
 public void doSecond() {
   System.out.println("执行doSecond()...");
 }

}

JDK * 类:


package com.ietree.basicskill.designpattern.dynamicproxy.jdk;

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

public class Main {
 public static void main(String[] args) {

final ISomeService target = new SomeServiceImpl();

// 使用JDK的Proxy * ,要求目标类和代理类必须实现相同的接口,因为其底层的执行原理与静态代理的相同
   ISomeService service = (ISomeService) Proxy.newProxyInstance(
       // 目标类的类加载器
       target.getClass().getClassLoader(),
       // 目标类所实现的所有接口
       target.getClass().getInterfaces(),
       new InvocationHandler() {
         // proxy:代理对象
         // method:目标方法
         // args:目标方法的参数列表
         @Override
         public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
           // 调用目标方法
           Object result = method.invoke(target, args);
           if (result != null) {
             result = ((String) result).toUpperCase();
           }
           return result;
         }
       });
   String result = service.doFirst();
   System.out.println(result);

service.doSecond();
 }
}

三、cglib *

Cglib是一个优秀的 * 框架,它的底层使用ASM在内存中动态的生成被代理类的子类,使用CGLIB即使代理类没有实现任何接口也可以实现 * 功能。CGLIB具有简单易用,它的运行速度要远远快于JDK的Proxy * :

CGLIB的核心类:

net.sf.cglib.proxy.Enhancer – 主要的增强类

net.sf.cglib.proxy.MethodInterceptor – 主要的方法拦截类,它是Callback接口的子接口,需要用户实现

net.sf.cglib.proxy.MethodProxy – JDK的java.lang.reflect.Method类的代理类,可以方便的实现对源对象方法的调用,如使用:

Object o = methodProxy.invokeSuper(proxy, args);//虽然第一个参数是被代理对象,也不会出现死循环的问题。

net.sf.cglib.proxy.MethodInterceptor接口是最通用的回调(callback)类型,它经常被基于代理的AOP用来实现拦截(intercept)方法的调用。这个接口只定义了一个方法

public Object intercept(Object object, java.lang.reflect.Method method, Object[] args, MethodProxy proxy) throws Throwable;

第一个参数是代理对像,第二和第三个参数分别是拦截的方法和方法的参数。原来的方法可能通过使用java.lang.reflect.Method对象的一般反射调用,或者使用 net.sf.cglib.proxy.MethodProxy对象调用。net.sf.cglib.proxy.MethodProxy通常被首选使用,因为它更快。

以下程序实现了大小写转换的功能:

实现类SomeService:


package com.ietree.basicskill.designpattern.dynamicproxy.cglib;

/**
* 实现类
*
* @author Root
*/
public class SomeService {

public String doFirst() {
   System.out.println("执行doFirst()...");
   String result = "abcde";
   return result;
 }

public void doSecond() {
   System.out.println("执行doSecond()...");
 }

}

代理类MyCglibFactory:


package com.ietree.basicskill.designpattern.dynamicproxy.cglib;

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 MyCglibFactory implements MethodInterceptor {

private SomeService target;

public MyCglibFactory() {
   super();
   target = new SomeService();
 }

public SomeService myCglibCreator() {
   // 创建增强器对象
   Enhancer enhancer = new Enhancer();
   // 指定目标类,即父类
   enhancer.setSuperclass(SomeService.class);
   // 设置回调接口对象
   enhancer.setCallback(this);

return (SomeService) enhancer.create();
 }

@Override
 public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
   // 调用目标方法
   Object result = method.invoke(target, args);
   if (result != null) {
     result = ((String) result).toUpperCase();
   }
   return result;
 }

}

测试:


package com.ietree.basicskill.designpattern.dynamicproxy.cglib;

public class Main {
 public static void main(String[] args) {

SomeService service = new MyCglibFactory().myCglibCreator();

String result = service.doFirst();
   System.out.println("result = " + result);

service.doSecond();
 }
}

运行结果:


执行doFirst()...
result = ABCDE
执行doSecond()...
标签:设计模式, ,
0
投稿

猜你喜欢

  • IDEA代码规范插件P3C+代码注释模板配置方法

    2022-10-30 17:32:55
  • c# 实现MD5,SHA1,SHA256,SHA512等常用加密算法源代码

    2021-11-22 22:18:24
  • Springboot整合mqtt服务的示例代码

    2022-07-20 02:58:01
  • Java找不到或无法加载主类及编码错误问题的解决方案

    2021-08-01 03:43:10
  • C++ Boost Fusion创建异构容器详解

    2021-12-30 23:52:58
  • Java基于分治算法实现的棋盘覆盖问题示例

    2021-07-17 14:05:16
  • c#唯一值渲染实例代码

    2023-09-06 06:54:16
  • Springboot+Mybatis-plus不使用SQL语句进行多表添加操作及问题小结

    2021-09-30 10:31:10
  • Windows下C#的GUI窗口程序中实现调用Google Map的实例

    2022-01-10 10:31:07
  • Android实现给TableLayou绘制边框的方法

    2021-08-04 02:08:41
  • 腾讯云部署javaWeb项目的实现步骤

    2023-11-05 18:03:29
  • Java语言实现快速幂取模算法详解

    2022-06-08 13:18:51
  • IntelliJ IDEA安装插件阿里巴巴Java开发手册(Alibaba Java Coding Guidelines)

    2023-10-17 11:30:02
  • Java反射机制在Spring IOC中的应用详解

    2023-11-10 14:09:32
  • 微信公众号开发之回复图文消息java代码

    2022-11-24 00:56:19
  • Java Idea TranslationPlugin翻译插件使用解析

    2023-12-01 10:25:02
  • Android Studio 3.1.3升级至3.6.1后旧项目的兼容操作方法

    2022-03-27 10:15:41
  • Android中使用TagFlowLayout制作动态添加删除标签

    2023-03-13 12:41:44
  • java多线程CyclicBarrier的使用案例,让线程起步走

    2023-05-20 16:22:22
  • Java实现调用外部程序的示例代码

    2023-11-10 06:43:12
  • asp之家 软件编程 m.aspxhome.com