什么是CGLIB,CGLIB使用简介,cglib

article/2025/10/31 13:27:23

什么是CGLIB,CGLIB使用简介

2018年08月20日 10:41:31 axiaositong 阅读数:348

什么是CGLIB

CGLIB是一个强大的、高性能的代码生成库。其被广泛应用于AOP框架(Spring、dynaop)中,用以提供方法拦截操作。Hibernate作为一个比较受欢迎的ORM框架,同样使用CGLIB来代理单端(多对一和一对一)关联(延迟提取集合使用的另一种机制)。CGLIB作为一个开源项目,其代码托管在github,地址为:https://github.com/cglib/cglib

为什么使用CGLIB

CGLIB代理主要通过对字节码的操作,为对象引入间接级别,以控制对象的访问。我们知道Java中有一个动态代理也是做这个事情的,那我们为什么不直接使用Java动态代理,而要使用CGLIB呢?答案是CGLIB相比于JDK动态代理更加强大,JDK动态代理虽然简单易用,但是其有一个致命缺陷是,只能对接口进行代理。如果要代理的类为一个普通类、没有接口,那么Java动态代理就没法使用了。关于Java动态代理,可以参者这里Java动态代理分析

CGLIB组成结构

image

CGLIB底层使用了ASM(一个短小精悍的字节码操作框架)来操作字节码生成新的类。除了CGLIB库外,脚本语言(如Groovy何BeanShell)也使用ASM生成字节码。ASM使用类似SAX的解析器来实现高性能。我们不鼓励直接使用ASM,因为它需要对Java字节码的格式足够的了解

例子

说了这么多,可能大家还是不知道CGLIB是干什么用的。下面我们将使用一个简单的例子来演示如何使用CGLIB对一个方法进行拦截。 
首先,我们需要在工程的POM文件中引入cglib的dependency,这里我们使用的是2.2.2版本

 
  1. <dependency>

  2. <groupId>cglib</groupId>

  3. <artifactId>cglib</artifactId>

  4. <version>2.2.2</version>

  5. </dependency>

依赖包下载后,我们就可以干活了,按照国际惯例,写个hello world

 
  1. public class SampleClass {

  2. public void test(){

  3. System.out.println("hello world");

  4. }

  5.  
  6. public static void main(String[] args) {

  7. Enhancer enhancer = new Enhancer();

  8. enhancer.setSuperclass(SampleClass.class);

  9. enhancer.setCallback(new MethodInterceptor() {

  10. @Override

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

  12. System.out.println("before method run...");

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

  14. System.out.println("after method run...");

  15. return result;

  16. }

  17. });

  18. SampleClass sample = (SampleClass) enhancer.create();

  19. sample.test();

  20. }

  21. }

在mian函数中,我们通过一个Enhancer和一个MethodInterceptor来实现对方法的拦截,运行程序后输出为:

 
  1. before method run...

  2. hello world

  3. after method run...

在上面的程序中,我们引入了Enhancer和MethodInterceptor,可能有些读者还不太了解。别急,我们后面将会一一进行介绍。就目前而言,一个使用CGLIB的小demo就完成了

常用的API

目前网络上对CGLIB的介绍资料比较少,造成对cglib的学习困难。这里我将对cglib中的常用类进行一个介绍。为了避免解释的不清楚,我将为每个类都配有一个demo,用来做进一步的说明。首先就从Enhancer开始吧。

Enhancer

Enhancer可能是CGLIB中最常用的一个类,和Java1.3动态代理中引入的Proxy类差不多(如果对Proxy不懂,可以参考这里)。和Proxy不同的是,Enhancer既能够代理普通的class,也能够代理接口。Enhancer创建一个被代理对象的子类并且拦截所有的方法调用(包括从Object中继承的toString和hashCode方法)。Enhancer不能够拦截final方法,例如Object.getClass()方法,这是由于Java final方法语义决定的。基于同样的道理,Enhancer也不能对fianl类进行代理操作。这也是Hibernate为什么不能持久化final class的原因。

 
  1. public class SampleClass {

  2. public String test(String input){

  3. return "hello world";

  4. }

  5. }

下面我们将以这个类作为主要的测试类,来测试调用各种方法

 
  1. @Test

  2. public void testFixedValue(){

  3. Enhancer enhancer = new Enhancer();

  4. enhancer.setSuperclass(SampleClass.class);

  5. enhancer.setCallback(new FixedValue() {

  6. @Override

  7. public Object loadObject() throws Exception {

  8. return "Hello cglib";

  9. }

  10. });

  11. SampleClass proxy = (SampleClass) enhancer.create();

  12. System.out.println(proxy.test(null)); //拦截test,输出Hello cglib

  13. System.out.println(proxy.toString());

  14. System.out.println(proxy.getClass());

  15. System.out.println(proxy.hashCode());

  16. }

程序的输出为:

 
  1. Hello cglib

  2. Hello cglib

  3. class com.zeus.cglib.SampleClass$$EnhancerByCGLIB$$e3ea9b7

  4.  
  5. java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Number

  6.  
  7. at com.zeus.cglib.SampleClass$$EnhancerByCGLIB$$e3ea9b7.hashCode(<generated>)

  8. ...

上述代码中,FixedValue用来对所有拦截的方法返回相同的值,从输出我们可以看出来,Enhancer对非final方法test()、toString()、hashCode()进行了拦截,没有对getClass进行拦截。由于hashCode()方法需要返回一个Number,但是我们返回的是一个String,这解释了上面的程序中为什么会抛出异常。

Enhancer.setSuperclass用来设置父类型,从toString方法可以看出,使用CGLIB生成的类为被代理类的一个子类,形如:SampleClass

EnhancerByCGLIBEnhancerByCGLIB

e3ea9b7

Enhancer.create(Object…)方法是用来创建增强对象的,其提供了很多不同参数的方法用来匹配被增强类的不同构造方法。(虽然类的构造放法只是Java字节码层面的函数,但是Enhancer却不能对其进行操作。Enhancer同样不能操作static或者final类)。我们也可以先使用Enhancer.createClass()来创建字节码(.class),然后用字节码动态的生成增强后的对象。

可以使用一个InvocationHandler(如果对InvocationHandler不懂,可以参考这里)作为回调,使用invoke方法来替换直接访问类的方法,但是你必须注意死循环。因为invoke中调用的任何原代理类方法,均会重新代理到invoke方法中。

 
  1. public void testInvocationHandler() throws Exception{

  2. Enhancer enhancer = new Enhancer();

  3. enhancer.setSuperclass(SampleClass.class);

  4. enhancer.setCallback(new InvocationHandler() {

  5. @Override

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

  7. if(method.getDeclaringClass() != Object.class && method.getReturnType() == String.class){

  8. return "hello cglib";

  9. }else{

  10. throw new RuntimeException("Do not know what to do");

  11. }

  12. }

  13. });

  14. SampleClass proxy = (SampleClass) enhancer.create();

  15. Assert.assertEquals("hello cglib", proxy.test(null));

  16. Assert.assertNotEquals("Hello cglib", proxy.toString());

  17. }

为了避免这种死循环,我们可以使用MethodInterceptor,MethodInterceptor的例子在前面的hello world中已经介绍过了,这里就不浪费时间了。

有些时候我们可能只想对特定的方法进行拦截,对其他的方法直接放行,不做任何操作,使用Enhancer处理这种需求同样很简单,只需要一个CallbackFilter即可:

 
  1. @Test

  2. public void testCallbackFilter() throws Exception{

  3. Enhancer enhancer = new Enhancer();

  4. CallbackHelper callbackHelper = new CallbackHelper(SampleClass.class, new Class[0]) {

  5. @Override

  6. protected Object getCallback(Method method) {

  7. if(method.getDeclaringClass() != Object.class && method.getReturnType() == String.class){

  8. return new FixedValue() {

  9. @Override

  10. public Object loadObject() throws Exception {

  11. return "Hello cglib";

  12. }

  13. };

  14. }else{

  15. return NoOp.INSTANCE;

  16. }

  17. }

  18. };

  19. enhancer.setSuperclass(SampleClass.class);

  20. enhancer.setCallbackFilter(callbackHelper);

  21. enhancer.setCallbacks(callbackHelper.getCallbacks());

  22. SampleClass proxy = (SampleClass) enhancer.create();

  23. Assert.assertEquals("Hello cglib", proxy.test(null));

  24. Assert.assertNotEquals("Hello cglib",proxy.toString());

  25. System.out.println(proxy.hashCode());

  26. }

ImmutableBean

通过名字就可以知道,不可变的Bean。ImmutableBean允许创建一个原来对象的包装类,这个包装类是不可变的,任何改变底层对象的包装类操作都会抛出IllegalStateException。但是我们可以通过直接操作底层对象来改变包装类对象。这有点类似于Guava中的不可变视图

为了对ImmutableBean进行测试,这里需要再引入一个bean

 
  1. public class SampleBean {

  2. private String value;

  3.  
  4. public SampleBean() {

  5. }

  6.  
  7. public SampleBean(String value) {

  8. this.value = value;

  9. }

  10. public String getValue() {

  11. return value;

  12. }

  13.  
  14. public void setValue(String value) {

  15. this.value = value;

  16. }

  17. }

  •  

然后编写测试类如下:

 
  1. @Test(expected = IllegalStateException.class)

  2. public void testImmutableBean() throws Exception{

  3. SampleBean bean = new SampleBean();

  4. bean.setValue("Hello world");

  5. SampleBean immutableBean = (SampleBean) ImmutableBean.create(bean); //创建不可变类

  6. Assert.assertEquals("Hello world",immutableBean.getValue());

  7. bean.setValue("Hello world, again"); //可以通过底层对象来进行修改

  8. Assert.assertEquals("Hello world, again", immutableBean.getValue());

  9. immutableBean.setValue("Hello cglib"); //直接修改将throw exception

  10. }

Bean generator

cglib提供的一个操作bean的工具,使用它能够在运行时动态的创建一个bean。

 
  1. @Test

  2. public void testBeanGenerator() throws Exception{

  3. BeanGenerator beanGenerator = new BeanGenerator();

  4. beanGenerator.addProperty("value",String.class);

  5. Object myBean = beanGenerator.create();

  6. Method setter = myBean.getClass().getMethod("setValue",String.class);

  7. setter.invoke(myBean,"Hello cglib");

  8.  
  9. Method getter = myBean.getClass().getMethod("getValue");

  10. Assert.assertEquals("Hello cglib",getter.invoke(myBean));

  11. }

在上面的代码中,我们使用cglib动态的创建了一个和SampleBean相同的Bean对象,包含一个属性value以及getter、setter方法

Bean Copier

cglib提供的能够从一个bean复制到另一个bean中,而且其还提供了一个转换器,用来在转换的时候对bean的属性进行操作。

 
  1. public class OtherSampleBean {

  2. private String value;

  3.  
  4. public String getValue() {

  5. return value;

  6. }

  7.  
  8. public void setValue(String value) {

  9. this.value = value;

  10. }

  11. }

  12.  
  13. @Test

  14. public void testBeanCopier() throws Exception{

  15. BeanCopier copier = BeanCopier.create(SampleBean.class, OtherSampleBean.class, false);//设置为true,则使用converter

  16. SampleBean myBean = new SampleBean();

  17. myBean.setValue("Hello cglib");

  18. OtherSampleBean otherBean = new OtherSampleBean();

  19. copier.copy(myBean, otherBean, null); //设置为true,则传入converter指明怎么进行转换

  20. assertEquals("Hello cglib", otherBean.getValue());

  21. }

BulkBean

相比于BeanCopier,BulkBean将copy的动作拆分为getPropertyValues和setPropertyValues两个方法,允许自定义处理属性

 
  1. @Test

  2. public void testBulkBean() throws Exception{

  3. BulkBean bulkBean = BulkBean.create(SampleBean.class,

  4. new String[]{"getValue"},

  5. new String[]{"setValue"},

  6. new Class[]{String.class});

  7. SampleBean bean = new SampleBean();

  8. bean.setValue("Hello world");

  9. Object[] propertyValues = bulkBean.getPropertyValues(bean);

  10. assertEquals(1, bulkBean.getPropertyValues(bean).length);

  11. assertEquals("Hello world", bulkBean.getPropertyValues(bean)[0]);

  12. bulkBean.setPropertyValues(bean,new Object[]{"Hello cglib"});

  13. assertEquals("Hello cglib", bean.getValue());

  14. }

使用注意: 
1. 避免每次进行BulkBean.create创建对象,一般将其声明为static的 
2. 应用场景:针对特定属性的get,set操作,一般适用通过xml配置注入和注出的属性,运行时才确定处理的Source,Target类,只需要关注属性名即可。

BeanMap

BeanMap类实现了Java Map,将一个bean对象中的所有属性转换为一个String-to-Obejct的Java Map

 
  1. @Test

  2. public void testBeanMap() throws Exception{

  3. BeanGenerator generator = new BeanGenerator();

  4. generator.addProperty("username",String.class);

  5. generator.addProperty("password",String.class);

  6. Object bean = generator.create();

  7. Method setUserName = bean.getClass().getMethod("setUsername", String.class);

  8. Method setPassword = bean.getClass().getMethod("setPassword", String.class);

  9. setUserName.invoke(bean, "admin");

  10. setPassword.invoke(bean,"password");

  11. BeanMap map = BeanMap.create(bean);

  12. Assert.assertEquals("admin", map.get("username"));

  13. Assert.assertEquals("password", map.get("password"));

  14. }

我们使用BeanGenerator生成了一个含有两个属性的Java Bean,对其进行赋值操作后,生成了一个BeanMap对象,通过获取值来进行验证

keyFactory

keyFactory类用来动态生成接口的实例,接口需要只包含一个newInstance方法,返回一个Object。keyFactory为构造出来的实例动态生成了Object.equals和Object.hashCode方法,能够确保相同的参数构造出的实例为单例的。

 
  1. public interface SampleKeyFactory {

  2. Object newInstance(String first, int second);

  3. }

我们首先构造一个满足条件的接口,然后进行测试

 
  1. @Test

  2. public void testKeyFactory() throws Exception{

  3. SampleKeyFactory keyFactory = (SampleKeyFactory) KeyFactory.create(SampleKeyFactory.class);

  4. Object key = keyFactory.newInstance("foo", 42);

  5. Object key1 = keyFactory.newInstance("foo", 42);

  6. Assert.assertEquals(key,key1);//测试参数相同,结果是否相等

  7. }

Mixin(混合)

Mixin能够让我们将多个对象整合到一个对象中去,前提是这些对象必须是接口的实现。可能这样说比较晦涩,以代码为例:

 
  1. public class MixinInterfaceTest {

  2. interface Interface1{

  3. String first();

  4. }

  5. interface Interface2{

  6. String second();

  7. }

  8.  
  9. class Class1 implements Interface1{

  10. @Override

  11. public String first() {

  12. return "first";

  13. }

  14. }

  15.  
  16. class Class2 implements Interface2{

  17. @Override

  18. public String second() {

  19. return "second";

  20. }

  21. }

  22.  
  23. interface MixinInterface extends Interface1, Interface2{

  24.  
  25. }

  26.  
  27. @Test

  28. public void testMixin() throws Exception{

  29. Mixin mixin = Mixin.create(new Class[]{Interface1.class, Interface2.class,

  30. MixinInterface.class}, new Object[]{new Class1(),new Class2()});

  31. MixinInterface mixinDelegate = (MixinInterface) mixin;

  32. assertEquals("first", mixinDelegate.first());

  33. assertEquals("second", mixinDelegate.second());

  34. }

  35. }

Mixin类比较尴尬,因为他要求Minix的类(例如MixinInterface)实现一些接口。既然被Minix的类已经实现了相应的接口,那么我就直接可以通过纯Java的方式实现,没有必要使用Minix类。

String switcher

用来模拟一个String到int类型的Map类型。如果在Java7以后的版本中,类似一个switch语句。

 
  1. @Test

  2. public void testStringSwitcher() throws Exception{

  3. String[] strings = new String[]{"one", "two"};

  4. int[] values = new int[]{10,20};

  5. StringSwitcher stringSwitcher = StringSwitcher.create(strings,values,true);

  6. assertEquals(10, stringSwitcher.intValue("one"));

  7. assertEquals(20, stringSwitcher.intValue("two"));

  8. assertEquals(-1, stringSwitcher.intValue("three"));

  9. }

  • ace Maker

正如名字所言,Interface Maker用来创建一个新的Interface

 
  1. @Test

  2. public void testInterfaceMarker() throws Exception{

  3. Signature signature = new Signature("foo", Type.DOUBLE_TYPE, new Type[]{Type.INT_TYPE});

  4. InterfaceMaker interfaceMaker = new InterfaceMaker();

  5. interfaceMaker.add(signature, new Type[0]);

  6. Class iface = interfaceMaker.create();

  7. assertEquals(1, iface.getMethods().length);

  8. assertEquals("foo", iface.getMethods()[0].getName());

  9. assertEquals(double.class, iface.getMethods()[0].getReturnType());

  10. }

上述的Interface Maker创建的接口中只含有一个方法,签名为double foo(int)。Interface Maker与上面介绍的其他类不同,它依赖ASM中的Type类型。由于接口仅仅只用做在编译时期进行类型检查,因此在一个运行的应用中动态的创建接口没有什么作用。但是InterfaceMaker可以用来自动生成代码,为以后的开发做准备。

Method delegate

MethodDelegate主要用来对方法进行代理

 
  1. interface BeanDelegate{

  2. String getValueFromDelegate();

  3. }

  4.  
  5. @Test

  6. public void testMethodDelegate() throws Exception{

  7. SampleBean bean = new SampleBean();

  8. bean.setValue("Hello cglib");

  9. BeanDelegate delegate = (BeanDelegate) MethodDelegate.create(bean,"getValue", BeanDelegate.class);

  10. assertEquals("Hello cglib", delegate.getValueFromDelegate());

  11. }

  •  

关于Method.create的参数说明: 
1. 第二个参数为即将被代理的方法 
2. 第一个参数必须是一个无参数构造的bean。因此MethodDelegate.create并不是你想象的那么有用 
3. 第三个参数为只含有一个方法的接口。当这个接口中的方法被调用的时候,将会调用第一个参数所指向bean的第二个参数方法

缺点: 
1. 为每一个代理类创建了一个新的类,这样可能会占用大量的永久代堆内存 
2. 你不能代理需要参数的方法 
3. 如果你定义的接口中的方法需要参数,那么代理将不会工作,并且也不会抛出异常;如果你的接口中方法需要其他的返回类型,那么将抛出IllegalArgumentException

MulticastDelegate

  1. 多重代理和方法代理差不多,都是将代理类方法的调用委托给被代理类。使用前提是需要一个接口,以及一个类实现了该接口
  2. 通过这种interface的继承关系,我们能够将接口上方法的调用分散给各个实现类上面去。
  3. 多重代理的缺点是接口只能含有一个方法,如果被代理的方法拥有返回值,那么调用代理类的返回值为最后一个添加的被代理类的方法返回值
 
  1. public interface DelegatationProvider {

  2. void setValue(String value);

  3. }

  4.  
  5. public class SimpleMulticastBean implements DelegatationProvider {

  6. private String value;

  7. @Override

  8. public void setValue(String value) {

  9. this.value = value;

  10. }

  11.  
  12. public String getValue() {

  13. return value;

  14. }

  15. }

  16.  
  17. @Test

  18. public void testMulticastDelegate() throws Exception{

  19. MulticastDelegate multicastDelegate = MulticastDelegate.create(DelegatationProvider.class);

  20. SimpleMulticastBean first = new SimpleMulticastBean();

  21. SimpleMulticastBean second = new SimpleMulticastBean();

  22. multicastDelegate = multicastDelegate.add(first);

  23. multicastDelegate = multicastDelegate.add(second);

  24.  
  25. DelegatationProvider provider = (DelegatationProvider) multicastDelegate;

  26. provider.setValue("Hello world");

  27.  
  28. assertEquals("Hello world", first.getValue());

  29. assertEquals("Hello world", second.getValue());

  30. }

Constructor delegate

为了对构造函数进行代理,我们需要一个接口,这个接口只含有一个Object newInstance(…)方法,用来调用相应的构造函数

 
  1. interface SampleBeanConstructorDelegate{

  2. Object newInstance(String value);

  3. }

  4.  
  5. /**

  6. * 对构造函数进行代理

  7. * @throws Exception

  8. */

  9. @Test

  10. public void testConstructorDelegate() throws Exception{

  11. SampleBeanConstructorDelegate constructorDelegate = (SampleBeanConstructorDelegate) ConstructorDelegate.create(

  12. SampleBean.class, SampleBeanConstructorDelegate.class);

  13. SampleBean bean = (SampleBean) constructorDelegate.newInstance("Hello world");

  14. assertTrue(SampleBean.class.isAssignableFrom(bean.getClass()));

  15. System.out.println(bean.getValue());

  16. }

Parallel Sorter(并行排序器)

能够对多个数组同时进行排序,目前实现的算法有归并排序和快速排序

 
  1. @Test

  2. public void testParallelSorter() throws Exception{

  3. Integer[][] value = {

  4. {4, 3, 9, 0},

  5. {2, 1, 6, 0}

  6. };

  7. ParallelSorter.create(value).mergeSort(0);

  8. for(Integer[] row : value){

  9. int former = -1;

  10. for(int val : row){

  11. assertTrue(former < val);

  12. former = val;

  13. }

  14. }

  15. }

FastClass

顾明思义,FastClass就是对Class对象进行特定的处理,比如通过数组保存method引用,因此FastClass引出了一个index下标的新概念,比如getIndex(String name, Class[] parameterTypes)就是以前的获取method的方法。通过数组存储method,constructor等class信息,从而将原先的反射调用,转化为class.index的直接调用,从而体现所谓的FastClass。

 
  1. @Test

  2. public void testFastClass() throws Exception{

  3. FastClass fastClass = FastClass.create(SampleBean.class);

  4. FastMethod fastMethod = fastClass.getMethod("getValue",new Class[0]);

  5. SampleBean bean = new SampleBean();

  6. bean.setValue("Hello world");

  7. assertEquals("Hello world",fastMethod.invoke(bean, new Object[0]));

  8. }

注意

由于CGLIB的大部分类是直接对Java字节码进行操作,这样生成的类会在Java的永久堆中。如果动态代理操作过多,容易造成永久堆满,触发OutOfMemory异常。

CGLIB和Java动态代理的区别

  1. Java动态代理只能够对接口进行代理,不能对普通的类进行代理(因为所有生成的代理类的父类为Proxy,Java类继承机制不允许多重继承);CGLIB能够代理普通类;
  2. Java动态代理使用Java原生的反射API进行操作,在生成类上比较高效;CGLIB使用ASM框架直接对字节码进行操作,在类的执行过程中比较高效

http://chatgpt.dhexx.cn/article/AP9H4ylm.shtml

相关文章

(转帖)Cglib和jdk动态代理的区别及运行性能比较

动态代理解决了方法之间的紧耦合&#xff0c;IOC解决了类与类之间的紧耦合&#xff01; Cglib和jdk动态代理的区别&#xff1f; 1、Jdk动态代理&#xff1a;利用拦截器&#xff08;必须实现InvocationHandler&#xff09;加上反射机制生成一个代理接口的匿名类&#xff0c;在…

CGLib动态代理原理

CGLib动态代理原理 CGLib动态代理是代理类去继承目标类&#xff0c;然后重写其中目标类的方法啊&#xff0c;这样也可以保证代理类拥有目标类的同名方法&#xff1b; 看一下CGLib的基本结构&#xff0c;下图所示&#xff0c;代理类去继承目标类&#xff0c;每次调用代理类的方…

CGLib介绍

1. CGLIB介绍 CGLIB(Code Generation Library)是一个开源项目&#xff01;是一个强大的&#xff0c;高性能&#xff0c;高质量的Code生成类库&#xff0c; 它可以在运行期扩展Java类与实现Java接口。CGLIB是一个强大的高性能的代码生成包。它广泛的被许多AOP的框架使用&#…

cglib的简单使用

一、前言 最近在看Spring的源码&#xff0c;其中有牵扯到cglib的相关内容&#xff0c;遂简单记录下cglib是如何使用的 二、原理&#xff08;节选自网络&#xff09; CGLIB原理&#xff1a;动态生成一个要代理类的子类&#xff0c;子类重写要代理的类的所有不是final的方法。…

cglib动态代理

前面介绍了代理模式和JAVA动态代理&#xff0c;这片文章主要解析cglib动态代理实现。 基本介绍 CGLIB&#xff08;Code Generation Library&#xff09;&#xff0c;是一个强大的&#xff0c;高性能&#xff0c;高质量的 Code 生成类库&#xff0c;它可以在运行期扩展 Java 类…

动态代理之 cglib 实现

&#xff08;尊重劳动成果&#xff0c;转载请注明出处&#xff1a;https://blog.csdn.net/qq_25827845/article/details/87513102冷血之心的博客&#xff09; 目录 前言&#xff1a; 正文&#xff1a; AOP&#xff08;面向切面编程&#xff09; JDK动态代理 cglib实现动态…

CGLIB介绍与原理

一、什么是 CGLIB? CGLIB是一个功能强大&#xff0c;高性能的代码生成包。它为没有实现接口的类提供代理&#xff0c;为JDK的动态代理提供了很好的补充。通常可以使用Java的动态代理创建代理&#xff0c;但当要代理的类没有实现接口或者为了更好的性能&#xff0c;CGLIB是一个…

CGLIB(Code Generation Library)详解

什么是CGLIB CGLIB是一个强大的、高性能的代码生成库。其被广泛应用于AOP框架&#xff08;Spring、dynaop&#xff09;中&#xff0c;用以提供方法拦截操作。Hibernate作为一个比较受欢迎的ORM框架&#xff0c;同样使用CGLIB来代理单端&#xff08;多对一和一对一&#xff09;…

【动态代理】CGLIB 动态代理的使用及原理

1. CGLIB 动态代理介绍 什么是 CGLIB&#xff1f; CGLIB是一个功能强大&#xff0c;高性能的代码生成包。它为没有实现接口的类提供代理&#xff0c;为JDK的动态代理提供了很好的补充。 通常可以使用Java的动态代理创建代理&#xff0c;但当要代理的类没有实现接口或者为了更…

CGLIB详解(最详细)

转载地址:https://blog.csdn.net/danchu/article/details/70238002 什么是CGLIB CGLIB是一个强大的、高性能的代码生成库。其被广泛应用于AOP框架&#xff08;Spring、dynaop&#xff09;中&#xff0c;用以提供方法拦截操作。Hibernate作为一个比较受欢迎的ORM框架&#xff0c…

GPG error解决方案

问题: sudo apt-get update时报错GPG error 解决方案: // F42ED6FBAB17C654是根据你报错那一行确定的 sudo gpg --keyserver keyserver.ubuntu.com --recv F42ED6FBAB17C654 sudo gpg --export --armor F42ED6FBAB17C654 | sudo apt-key add -然后: sudo apt-get update

GPG Keys are configured as: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-mysql

阿里云CentOS 7.9 64位 搭建网站踩坑实录 问题1.GPG Keys are configured as: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-mysql Failing package is: mysql-community-libs-compat-5.7.37-1.el7.x86_64 GPG Keys are configured as: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-mysql …

gpg文件加密解密

使用Ubuntu对文件进行gpg格式的加密和解密 安装 下载源码安装  ./configure   make   make install 命令安装 Debian环境 sudo apt-get install gnupg Fedora 环境 yum install gnupg 加密 gpg -c abc.txt 会让输入一个加密的密码&#xff0c;需要自己输入 解密 gpg -o …

GPG(GnuPG)的安装和使用

基于网络的开源项目&#xff0c;能给用户带来在公共标准基础上的自由发挥&#xff0c;并且能很好地给每个自愿人士提供了共享贡献的机会。但是&#xff0c;同时也因为大众化给使用共享的程序员或团队带来了安全性问题。 当程序员从中央仓库下载第三方构件的时候&#xff0c;下载…

gpg使用

https://blog.csdn.net/weixin_42559321/article/details/82147888 https://www.cnblogs.com/wanghongli/archive/2018/01/08/8241809.html rpm2cpio *.rpm | cpio -imd       #解压一个rpm包rpm -ivh *.rpm --force       #强制安装这个rpm包rpm -iv…

如何在Git中使用GPG

开篇之前&#xff0c;先给大伙看点东西 是不是很想要&#xff1f;你找对地方了! 下面是教程&#xff1a; 在 “开始”菜单 打开Git Bash 输入 gpg --gen-key 显示如下 $ gpg --gen-keygpg (GnuPG) 2.2.13-unknown; Copyright (C) 2019 Free Software Foundation, Inc.This …

成功解决gpg: 找不到有效的 OpenPGP 数据

在Ubuntu系统上安装docker时出现gpg: 找不到有效的 OpenPGP 数据的报错 解决方案&#xff1a; wget https://download.docker.com/linux/ubuntu/gpg sudo apt-key add gpg随后再次执行下载指令&#xff0c;解决报错 成功解决gpg: 找不到有效的 OpenPGP 数据的报错 欢迎小伙…

GPG Overview

Overview PGP目前支持的算法 非对称算法: RSA, ELG, DSA, ECDH, ECDSA, EDDSA对称算法: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH, CAMELLIA128, CAMELLIA192, CAMELLIA256哈希算法: SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224压缩算法: Uncompres…

GPG 使用初步

GPG 使用初步 1. PGP 软件的安装 PGP 的版本有很多&#xff0c;但由于其商业软件的特性&#xff0c;不能自由使用&#xff0c;自由软件基金会决定开发一个 PGP 的替代品&#xff0c;取名为 GnuPG &#xff0c;这就是 PGP 的由来   GPG 是基于命令行的程序&#xff0c;主要面…

gpg加解密软件学习

为什么要学习gpg呢&#xff1f;因为要在Linux下把一个邮箱的密码加密&#xff0c;不让其他人看到该邮箱真正的密码。 为了不让其他人看到真正的邮箱密码&#xff0c;我们需要对其进行加密。 加密的方式是先把密码先写到一个文件A中&#xff0c;然后使用相关的加密软件对该文件…