java * 和cglib * 示例分享

时间:2023-10-26 18:36:02 

java * 类可以分为两种。

静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。

* :在程序运行时,运用反射机制动态创建而成。

一、首先我们进行java * 的演示。

现在我们有一个简单的业务接口Saying,如下:


package testAOP;
public interface Saying {
public void sayHello(String name);   
public void talking(String name);
}

一个简单的实现类SayingImpl,如下:


package testAOP;
public class SayingImpl implements Saying {
    @Override
    public void sayHello(String name) {
        // TODO Auto-generated method stub
        System.out.println(name + ":大家好啊!");
    }
    @Override
    public void talking(String name) {
        // TODO Auto-generated method stub
        System.out.println(name + ":我的意思是,我们要努力建设和谐社会!");
    }
}

我们要实现的是,在sayHello和talking之前和之后分别动态植入处理。

JDK * 主要用到java.lang.reflect包中的两个类:Proxy和InvocationHandler.

InvocationHandler是一个接口,通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态的将横切逻辑和业务逻辑编织在一起。

Proxy利用InvocationHandler动态创建一个符合某一接口的实例,生成目标类的代理对象。

如下,我们创建一个InvocationHandler实例:


package testAOP;

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

public class MyInvocationHandler implements InvocationHandler {

    private Object target;
    MyInvocationHandler(Object target){
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        //目标方法前执行
        System.out.println("——————————————————————————");
        System.out.println("下一位请登台发言!");
        //目标方法调用
        Object obj = method.invoke(target, args);
        //目标方法后执行
        System.out.println("大家掌声鼓励!");
        return obj;
    }
}

下面是测试:


package testAOP;
import java.lang.reflect.Proxy;
public class JDKProxyTest {

    public static void main(String[] args) {
        // 希望被代理的目标业务类
        Saying target = new SayingImpl();
        // 将目标类和横切类编织在一起
        MyInvocationHandler handler = new MyInvocationHandler(target);
        // 创建代理实例
        Saying proxy = (Saying) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),//目标类的类加载器
                target.getClass().getInterfaces(),//目标类的接口
                handler);//横切类
        proxy.sayHello("小明");
        proxy.talking("小丽");
    }
}

运行情况如下:


——————————————————————————
下一位请登台发言!
小明:大家好啊!
大家掌声鼓励!
——————————————————————————
下一位请登台发言!
小丽:我的意思是,我们要努力建设和谐社会!
大家掌声鼓励!

使用JDK * 有一个很大的限制,就是它要求目标类必须实现了对应方法的接口,它只能为接口创建代理实例。我们在上文测试类中的Proxy的newProxyInstance方法中可以看到,该方法第二个参数便是目标类的接口。如果该类没有实现接口,这就要靠cglib * 了。

CGLib采用非常底层的字节码技术,可以为一个类创建一个子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,并顺势植入横切逻辑。

二、接下来我们进行cglib * 的演示。

首先我们需要导包,我用的包是cglib-nodep-2.1_3.jar。

我们首先创建一个代理创建器CglibProxy:


package testAOP.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 CglibProxy implements MethodInterceptor{

    Enhancer enhancer = new Enhancer();
    public Object getProxy(Class clazz) {
        //设置需要创建的子类
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        //通过字节码技术动态创建子类实例
        return enhancer.create();
    }
    @Override
    public Object intercept(Object obj, Method method, Object[] args,
            MethodProxy proxy) throws Throwable {
        // TODO Auto-generated method stub
        System.out.println("——————————————————————————");
        System.out.println("下一位请登台发言!");
        //目标方法调用
        Object result = proxy.invokeSuper(obj, args);
        //目标方法后执行
        System.out.println("大家掌声鼓励!");
        return result;
    }   
}

然后进行测试:


package testAOP.cglib;
import testAOP.Saying;
import testAOP.SayingImpl;
public class CglibProxyTest {

    public static void main(String[] args) {
        CglibProxy proxy = new CglibProxy();
        //通过动态生成子类的方式创建代理类
        Saying target = (Saying) proxy.getProxy(SayingImpl.class);
        target.sayHello("小明");
        target.talking("小丽");
    }
}

结果与JDK * 没有任何区别。

JDK * 和CGLib * 都是运行时增强,通过将横切代码植入代理类的方式增强。与此不同的是AspectJ,它能够在通过特殊的编译器在编译时期将横切代码植入增强,这样的增强处理在运行时候更有优势,因为JDK * 和CGLib * 每次运行都需要增强。

标签:java, , ,cglib
0
投稿

猜你喜欢

  • C++实现图书管理系统

    2023-11-03 03:00:35
  • Android SQLite数据库操作代码类分享

    2022-03-03 06:43:25
  • 浅谈java并发之计数器CountDownLatch

    2023-03-21 23:42:59
  • C#中dotnetcharting的用法实例详解

    2023-07-08 07:42:35
  • .Net Winform开发笔记(四)透过现象看本质

    2022-06-22 09:36:24
  • java.lang.NoClassDefFoundError错误解决办法

    2021-12-29 03:52:27
  • Windows编写jar启动脚本和关闭脚本的操作方法

    2021-05-28 04:36:58
  • Android实战教程第七篇之如何在内存中存储用户名和密码

    2021-07-15 15:43:14
  • Spring bean的实例化和IOC依赖注入详解

    2023-11-23 23:57:15
  • C#图像亮度调式与伪彩色图的处理教程(推荐)

    2022-03-26 19:43:54
  • 深入理解Spring事务原理

    2022-01-18 04:16:39
  • Android实现View滑动效果的6种方法

    2023-01-29 15:12:19
  • 基于XML配置Spring的自动装配过程解析

    2023-02-28 00:42:12
  • Java网络编程UDP实现多线程在线聊天

    2022-01-08 21:48:32
  • java绘制五子棋棋盘

    2022-05-10 09:37:36
  • C#实现WPF项目复制和移动文件夹

    2023-06-07 16:49:16
  • MyBatisPlus中CRUD使用方法详解

    2023-04-10 18:31:43
  • 完美解决客户端webview持有的页面缓存,不会立即释放的问题

    2021-09-23 03:30:50
  • Jmeter环境搭建及安装步骤

    2021-11-03 21:06:10
  • JavaSwing BorderLayout 边界布局的实现代码

    2023-04-23 08:03:40
  • asp之家 软件编程 m.aspxhome.com