- 使用 Spring Initializr 创建 Spring Boot 应用程序
- 在Spring Boot中配置Cassandra
- 在 Spring Boot 上配置 Tomcat 连接池
- 将Camel消息路由到嵌入WildFly的Artemis上
转载:简述CGLIB常用API
类似:【Spring】CGLIB动态代理
CGLIB,即Code Generation Library,是一个强大的、高性能的代码生成库
。其被广泛应用于AOP框架(例如Spring)中,用以提供方法拦截操作。Hibernate作为一个比较受欢迎的ORM框架,同样使用CGLIB来代理单端(多对一和一对一)关联(延迟提取集合使用的另一种机制)。CGLIB作为一个开源项目,其代码托管在github,地址为:https://github.com/cglib/cglib。
CGLIB的github简介:CGLIB - 字节码生成库,是用于生成和转换Java字节码的高级API。它被AOP、测试、数据访问框架用于生成动态代理对象和拦截字段访问。(原文:cglib - Byte Code Generation Library is high level API to generate and transform Java byte code. It is used by AOP, testing, data access frameworks to generate dynamic proxy objects and intercept field access.)
CGLIB提供两种类型的JAR包:
cglib-nodep-x.x.x.jar
:使用nodep包不需要关联ASM的jar包,也就是jar包内部包含ASM的类库。cglib-x.x.x.jar
:使用此jar包需要另外提供ASM的jar包,否则运行时报错,建议选用不包含ASM类库的jar包,可以方便控制ASM的。<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>3.2.10</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.22</version>
</dependency>
基本原理
:动态生成一个要代理类的子类(被代理的类作为继承的父类),子类重写要代理的类的所有不是final
的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。它比使用Java反射的JDK动态代理要快,因为它采用了整形变量建立了方法索引。
底层实现
:使用字节码处理框架ASM
,用于转换字节码并生成新的类。不鼓励直接使用ASM
,因为它要求必须对JVM内部结构包括class文件的格式和JVM指令集都很熟悉,否则一旦出现错误将会是JVM崩溃级别的异常
。
劣势
:对于final
方法或者final
的类,无法进行代理。
net.sf.cglib.core:底层字节码处理类,它们大部分与ASM有关系,在使用者角度来看不需要过多关注此包。
net.sf.cglib.transform:编译期或运行期类和类文件的转换。
net.sf.cglib.proxy:实现创建代理和方法拦截器的类。
net.sf.cglib.reflect:反射相关工具类。
net.sf.cglib.util:集合排序等工具类。
net.sf.cglib.beans:JavaBean相关的工具类。
下面介绍一下CGLIB中常用的API,先建立一个模特接口类和普通模特类:
public class SampleClass {
public String sayHello(String name) {
return String.format("%s say hello!", name);
}
}
public interface SampleInterface {
String sayHello(String name);
}
Enhancer,即(字节码)增强器
。它是CGLIB
库中最常用的一个类,功能JDK动态代理中引入的Proxy
类差不多,但是Enhancer
既能够代理普通的Java类,也能够代理接口
。
Enhancer创建一个被代理对象的子类并且拦截所有的方法调用(包括从Object中继承的toString和hashCode方法)。Enhancer不能够拦截final方法
,例如Object.getClass()
方法,这是由于final关键字的语义决定的。基于同样的道理,Enhancer也不能对fianl类进行代理操作。这也是Hibernate为什么不能持久化final关键字修饰的类的原因。
JAVA
public class EnhancerClassDemo {
public static void main(String[] args) throws Exception {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(SampleClass.class);
//使用FixedValue,拦截返回值,每次返回固定值"Doge say hello!"
enhancer.setCallback((FixedValue) () -> "Doge say hello!");
SampleClass sampleClass = (SampleClass) enhancer.create();
System.out.println(sampleClass.sayHello("throwable-10086"));
System.out.println(sampleClass.sayHello("throwable-doge"));
System.out.println(sampleClass.toString());
System.out.println(sampleClass.getClass());
System.out.println(sampleClass.hashCode());
}
}
输出结果:
Doge say hello!
Doge say hello!
Doge say hello!
class club.throwable.cglib.SampleClass$$EnhancerByCGLIB$$6f6e7a68
Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Number
......
上述代码中,FixedValue
用来对所有拦截的方法返回相同的值,从输出我们可以看出来,Enhancer对非final方法test()、toString()、hashCode()进行了拦截,没有对getClass进行拦截。由于hashCode()方法需要返回一个Number,但是我们返回的是一个String,这解释了上面的程序中为什么会抛出异常。
Enhancer3setSuperclass
()用来设置父类型,从toString()方法可以看出,使用CGLIB生成的类为被代理类的一个子类,类简写名称为SampleClass$$EnhancerByCGLIB$$e3ea9b7
。
Enhancer#create(Class[] argumentTypes, Object[] arguments)
方法是用来创建增强对象的,其提供了很多不同参数的方法用来匹配被增强类的不同构造方法。我们也可以先使用Enhancer#createClass()
来创建字节码(.class)
,然后用字节码加载完成后的类动态生成增强后的对象。Enhancer中还有其他几个方法名为create的方法,提供不同的参数选择,具体可以自行查阅。
下面再举个例子说明一下使用Enhancer代理接口:
JAVA
public class EnhancerInterfaceDemo {
public static void main(String[] args) throws Exception {
Enhancer enhancer = new Enhancer();
enhancer.setInterfaces(new Class[]{SampleInterface.class});
enhancer.setCallback((FixedValue) () -> "Doge say hello!");
SampleInterface sampleInterface = (SampleInterface) enhancer.create();
System.out.println(sampleInterface.sayHello("throwable-10086"));
System.out.println(sampleInterface.sayHello("throwable-doge"));
System.out.println(sampleInterface.toString());
System.out.println(sampleInterface.getClass());
System.out.println(sampleInterface.hashCode());
}
}
输出结果和上一个例子一致。
Callback,即回调
。值得注意的是,它是一个标识接口(空接口,没有任何方法),它的回调时机是生成的代理类的方法被调用的时候。也就是说,生成的代理类的方法被调用的时候,Callback的实现逻辑就会被调用。Enhancer通过setCallback()和setCallbacks()设置Callback,设置了多个Callback实例将会按照设置的顺序进行回调
。CGLIB中提供的Callback的子类有以下几种:
NoOp
FixedValue
InvocationHandler
MethodInterceptor
Dispatcher
LazyLoader
NoOp,No Operation,也就是不做任何操作。这个回调实现只是简单地把方法调用委托给了被代理类的原方法(也就是调用原始类的原始方法),不做任何其它的操作,所以不能使用在接口代理。
public class NoOpDemo {
public static void main(String[] args) throws Exception{
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(SampleClass.class);
enhancer.setCallback(NoOp.INSTANCE);
SampleClass sampleClass = (SampleClass) enhancer.create();
System.out.println(sampleClass.sayHello("throwable"));
}
}
输出结果:
throwable say hello!
FixedValue,Fixed Value,即固定值。它提供了一个loadObject
()方法,不过这个方法返回的不是代理对象,而是原方法调用想要的结果。也就是说,在这个Callback
里面,看不到任何原方法的信息,也就没有调用原方法的逻辑,不管原方法是什么都只会调用loadObject
()并返回一个固定结果。需要注意的是,如果loadObject
()方法的返回值并不能转换成原方法的返回值类型,那么会抛出类型转换异常(ClassCastException
)。
最前面的Enhancer两个例子就是用FixedValue做分析的,这里不再举例。
InvocationHandler
全类名为net.sf.cglib.proxy.InvocationHandler
,它的功能和JDK动态代理中的java.lang.reflect.InvocationHandler
类似,提供了一个Object invoke(Object proxy, Method method, Object[] objects)
方法。需要注意的是:所有对invoke方法的参数proxy对象的方法调用都会被委托给同一个InvocationHandler,所以可能会导致无限循环(因为invoke中调用的任何原代理类方法,均会重新代理到invoke方法中)。举个简单的例子:
public class InvocationHandlerDeadLoopDemo {
public static void main(String[] args) throws Exception{
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(SampleClass.class);
enhancer.setCallback(new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
return method.invoke(o, objects);
}
});
SampleClass sampleClass = (SampleClass) enhancer.create();
System.out.println(sampleClass.sayHello("throwable"));
}
}
上面的main方法执行后会直接爆栈,因为method#invoke()
方法会重新调用InvocationHandler的invoke方法,形成死循环。正确的使用例子如下:
public class InvocationHandlerDemo {
public static void main(String[] args) throws Exception {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(SampleClass.class);
enhancer.setCallback(new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
if (!Objects.equals(method.getDeclaringClass(), Object.class) && Objects.equals(String.class, method.getReturnType())) {
return String.format("%s say hello!", objects);
}
return "No one say hello!";
}
});
SampleClass sampleClass = (SampleClass) enhancer.create();
System.out.println(sampleClass.sayHello("throwable"));
}
}
输出结果:
throwable say hello!
MethodInterceptor,即方法拦截器,这是一个功能很强大的接口,它可以实现类似于AOP编程中的环绕增强(Around Advice)。它只有一个方法public Object intercept(Object obj,java.lang.reflect.Method method,Object[] args,MethodProxy methodProxy) throws Throwable。设置了MethodInterceptor后,代理类的所有方法调用都会转而执行这个接口中的intercept方法而不是原方法。如果需要在intercept方法中执行原方法可以使用参数method基于代理实例obj进行反射调用,但是使用方法代理methodProxy效率会更高(反射调用比正常的方法调用的速度慢很多)。MethodInterceptor的生成效率不高,它的优势在于调用效率,它需要产生不同类型的字节码,并且需要生成一些运行时对象(InvocationHandler就不需要)。注意,在使用MethodProxy调用invokeSuper方法相当于通过方法代理直接调用原类的对应方法,如果调用MethodProxy的invoke会进入死循环导致爆栈,原因跟InvocationHandler差不多。
public class MethodInterceptorDemo {
public static void main(String[] args) throws Exception {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(SampleClass.class);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("Before invoking sayHello...");
Object result = methodProxy.invokeSuper(obj, objects);
System.out.println("After invoking sayHello...");
return result;
}
});
SampleClass sampleClass = (SampleClass) enhancer.create();
System.out.println(sampleClass.sayHello("throwable"));
}
}
输出结果:
Before invoking sayHello...
After invoking sayHello...
throwable say hello!
这个例子就是Spring的AOP中的环绕增强(Around Advice)的简化版
,这里没有改变原来的方法的行为,只是在方法调用前和调用后织入额外的逻辑。
Dispatcher,即分发器,提供一个方法Object loadObject() throws Exception;
,同样地返回一个代理对象,这个对象同样可以代理原方法的调用。Dispatcher的loadObject()方法在每次发生对原方法的调用时都会被调用并返回一个代理对象来调用原方法。Dispatcher可以类比为Spring中的Prototype类型。
public class DispatcherDemo {
private static final AtomicInteger COUNTER = new AtomicInteger(0);
public static void main(String[] args) throws Exception {
Enhancer enhancer = new Enhancer();
SampleInterfaceImpl impl = new SampleInterfaceImpl();
enhancer.setInterfaces(new Class[]{SampleInterface.class});
enhancer.setCallback(new Dispatcher() {
@Override
public Object loadObject() throws Exception {
COUNTER.incrementAndGet();
return impl;
}
});
SampleInterface sampleInterface = (SampleInterface) enhancer.create();
System.out.println(sampleInterface.sayHello("throwable-1"));
System.out.println(sampleInterface.sayHello("throwable-2"));
System.out.println(COUNTER.get());
}
private static class SampleInterfaceImpl implements SampleInterface{
public SampleInterfaceImpl(){
System.out.println("SampleInterfaceImpl init...");
}
@Override
public String sayHello(String name) {
return "Hello i am SampleInterfaceImpl!";
}
}
}
输出结果:
SampleInterfaceImpl init...
Hello i am SampleInterfaceImpl!
Hello i am SampleInterfaceImpl!
2
计数器输出为2,印证了每次调用方法都会回调Dispatcher中的实例进行调用。
LazyLoader,即懒加载器,它只提供了一个方法Object loadObject() throws Exception;,loadObject()
方法会在第一次被代理类的方法调用时触发,它返回一个代理类的对象,这个对象会被存储起来然后负责所有被代理类方法的调用,就像它的名字说的那样,一种lazy加载模式。如果被代理类或者代理类的对象的创建比较麻烦,而且不确定它是否会被使用,那么可以选择使用这种lazy模式来延迟生成代理。LazyLoader可以类比为Spring中的Lazy模式的Singleton。
public class LazyLoaderDemo {
private static final AtomicInteger COUNTER = new AtomicInteger(0);
public static void main(String[] args) throws Exception {
Enhancer enhancer = new Enhancer();
SampleInterfaceImpl impl = new SampleInterfaceImpl();
enhancer.setInterfaces(new Class[]{SampleInterface.class});
enhancer.setCallback(new LazyLoader() {
@Override
public Object loadObject() throws Exception {
COUNTER.incrementAndGet();
return impl;
}
});
SampleInterface sampleInterface = (SampleInterface) enhancer.create();
System.out.println(sampleInterface.sayHello("throwable-1"));
System.out.println(sampleInterface.sayHello("throwable-2"));
System.out.println(COUNTER.get());
}
private static class SampleInterfaceImpl implements SampleInterface{
public SampleInterfaceImpl(){
System.out.println("SampleInterfaceImpl init...");
}
@Override
public String sayHello(String name) {
return "Hello i am SampleInterfaceImpl!";
}
}
}
输出结果:
SampleInterfaceImpl init...
Hello i am SampleInterfaceImpl!
Hello i am SampleInterfaceImpl!
1
计数器输出为1,印证了LazyLoader中的实例只回调了1次,这就是懒加载。
JavaBean属性拷贝器,提供从一个JavaBean实例中拷贝属性到另一个JavaBean实例中,注意类型必须完全匹配属性才能拷贝成功(原始类型和其包装类不属于相同类型)。它还提供了一个net.sf.cglib.core.Converter
转换器回调接口让使用者控制拷贝的过程。注意,BeanCopier内部使用了缓存和基于ASM动态生成BeanCopier的子类实现的转换方法中直接使用实例的Getter和Setter方法,拷贝速度极快(BeanCopier属性拷贝比直接的Setter、Getter稍慢,稍慢的原因在于首次需要动态生成BeanCopier的子类,一旦子类生成完成之后就和直接的Setter、Getter效率一致,但是效率远远高于其他使用反射的工具类库)。
public class BeanCopierDemo {
private static final Map<String, BeanCopier> CACHE = new ConcurrentHashMap<>();
public static void main(String[] args) throws Exception {
//这里useConverter设置为false,调用copy方法的时候不能传入转换器实例
BeanCopier beanCopier;
String key = generateCacheKey(Person.class, Person.class);
if (CACHE.containsKey(key)) {
beanCopier = CACHE.get(key);
} else {
beanCopier = BeanCopier.create(Person.class, Person.class, false);
CACHE.put(key, beanCopier);
}
Person person = new Person();
person.setId(10086L);
person.setName("throwable");
person.setAge(25);
Person newPerson = new Person();
beanCopier.copy(person, newPerson, null); //这里转换器实例要传null
System.out.println(newPerson);
}
private static String generateCacheKey(Class<?> source, Class<?> target) {
return String.format("%s-%s", source.getName(), target.getName());
}
@ToString
@Data
private static class Person {
private Long id;
private String name;
private Integer age;
}
}
输出结果:
BeanCopierDemo.Person(id=10086, name=throwable, age=25)
在使用BeanCopier时候最好缓存BeanCopier实例,因为构造BeanCopier实例是一个耗时的操作。
ImmutableBean,即不可变的Bean。ImmutableBean允许创建一个原来对象的包装类,这个包装类是不可变的,任何改变底层对象的包装类操作都会抛出IllegalStateException。但是我们可以通过直接操作底层对象来改变包装类对象。这有点类似于Guava中的不可变视图或者JDK中的不可变集合。
public class ImmutableBeanDemo {
public static void main(String[] args) throws Exception {
Person person = new Person();
person.setName("throwable");
Person immutablePerson = (Person) ImmutableBean.create(person);
System.out.println(immutablePerson.getName());
person.setName("doge");
System.out.println(immutablePerson.getName());
immutablePerson.setName("throwable-doge");
System.out.println(immutablePerson.getName());
}
@Data
private static class Person {
private String name;
}
}
输出结果:
throwable
doge
Exception in thread "main" java.lang.IllegalStateException: Bean is immutable
...
BeanGenerator,即Bean生成器,使用它能够在运行时动态的创建一个JavaBean。可以直接设置父类,生成的JavaBean就是父类类型的实例。
public class BeanGeneratorDemo {
public static void main(String[] args) throws Exception {
BeanGenerator beanGenerator = new BeanGenerator();
beanGenerator.addProperty("name", String.class);
Object target = beanGenerator.create();
Method setter = target.getClass().getDeclaredMethod("setName", String.class);
Method getter = target.getClass().getDeclaredMethod("getName");
setter.invoke(target, "throwable");
System.out.println(getter.invoke(target));
}
}
输出结果:
throwable
相比于BeanCopier,BulkBean创建时候依赖于确定的目标类型,Setter和Getter方法名称列表以及参数类型,它将copy的动作拆分为getPropertyValues()和setPropertyValues()两个方法,允许自定义处理属性。
public class BulkBeanDemo {
public static void main(String[] args) throws Exception {
BulkBean bulkBean = BulkBean.create(
Person.class,
new String[]{"getName"},
new String[]{"setName"},
new Class[]{String.class});
Person person = new Person();
person.setName("throwable");
Object[] propertyValues = bulkBean.getPropertyValues(person);
System.out.println(Arrays.toString(propertyValues));
bulkBean.setPropertyValues(person, new Object[]{"doge"});
System.out.println(person.getName());
}
@Data
private static class Person {
private String name;
}
}
输出结果:
[throwable]
doge
BeanMap类实现了JDK的java.util.Map接口,将一个JavaBean对象中的所有属性转换为一个String-To-Obejct的Map实例。
public class BeanMapDemo {
public static void main(String[] args) throws Exception{
Person person = new Person();
person.setName("throwable");
BeanMap beanMap = BeanMap.create(person);
System.out.println(beanMap);
System.out.println(beanMap.get("name"));
}
@Data
private static class Person {
private String name;
}
}
输出结果:
{name=throwable}
throwable
KeyFactory源码中的注释是:Generates classes to handle multi-valued keys, for use in things such as Maps and Sets. Code for equals and hashCode methods follow the the rules laid out in Effective Java by Joshua Bloch.(翻译一下:通过生成类来处理多值键,以便在诸如Map和集合之类的东西中使用。equals和hashCode方法的代码遵循Joshua Bloch在《Effective Java》中列出的规则)。
什么叫multi-valued keys?
就是有多个键的组合,一起作为一个Key。
比如[a b c]是一个组合,一起作为一个key,[2 3]也可以是作为一个key。
KeyFactory就是用来生成这样一组Key的,通过两组的equals,hashCode等方法判断是否为同一组key的场景。为了描述Key的组合,需要定义一个接口,仅提供一个方法,叫做newInstance(),且返回值为Object,这个是使用KeyFactory的要求。
public class KeyFactoryDemo {
public static void main(String[] args) throws Exception {
KeyFactoryInterface keyFactoryInterface1 = (KeyFactoryInterface) KeyFactory.create(KeyFactoryInterface.class);
KeyFactoryInterface keyFactoryInterface2 = (KeyFactoryInterface) KeyFactory.create(KeyFactoryInterface.class);
System.out.println(keyFactoryInterface1 == keyFactoryInterface2);
System.out.println(keyFactoryInterface1.equals(keyFactoryInterface2));
Object key1 = keyFactoryInterface1.newInstance(1, "doge");
Object key2 = keyFactoryInterface1.newInstance(1, "doge");
System.out.println(key1.equals(key2));
key2 = keyFactoryInterface1.newInstance(1, "doge10086");
System.out.println(key1.equals(key2));
}
interface KeyFactoryInterface {
Object newInstance(Integer a, String b);
}
}
输出结果:
false
true
true
false
Mixin能够让我们将多个接口的多个实现合并到同一个接口的单个实现。
public class MixinDemo {
interface InterfaceFirst {
String first();
}
interface InterfaceSecond {
String second();
}
static class ImplFirst implements InterfaceFirst {
@Override
public String first() {
return "I am first";
}
}
static class ImplSecond implements InterfaceSecond {
@Override
public String second() {
return "I am second";
}
}
interface MixinImpl extends InterfaceFirst, InterfaceSecond {
}
public static void main(String[] args) throws Exception {
Mixin mixin = Mixin.create(new Class[]{InterfaceFirst.class, InterfaceSecond.class, MixinImpl.class},
new Object[]{new ImplFirst(), new ImplSecond()});
MixinImpl mixinImpl = (MixinImpl) mixin;
System.out.println(mixinImpl.first());
System.out.println(mixinImpl.second());
}
}
输出结果:
I am first
I am second
用来模拟一个String到int类型的Map类型。如果在Java7以后的版本中,类似一个switch块的逻辑。
public class StringSwitcherDemo {
public static void main(String[] args) throws Exception {
StringSwitcher stringSwitcher = StringSwitcher.create(new String[]{"one", "two"}, new int[]{1, 2}, true);
System.out.println(stringSwitcher.intValue("one"));
System.out.println(stringSwitcher.intValue("two"));
}
}
输出结果:
1
2
接口生成器,底层依赖ASM的相关API。
public class InterfaceMakerDemo {
public static void main(String[] args) throws Exception {
Signature signature = new Signature("foo", Type.DOUBLE_TYPE, new Type[]{Type.INT_TYPE});
InterfaceMaker interfaceMaker = new InterfaceMaker();
interfaceMaker.add(signature, new Type[0]);
Class<?> clazz = interfaceMaker.create();
Method[] methods = clazz.getMethods();
System.out.println(methods.length);
Method foo = methods[0];
System.out.println(foo.getReturnType());
System.out.println(Arrays.toString(foo.getParameterTypes()));
}
}
输出结果:
1
double
[int]
上述的InterfaceMaker创建的接口中只含有一个方法,签名为double foo(int)。InterfaceMaker与上面介绍的其他类不同,它依赖ASM中的Type类型。由于接口仅仅只用做在编译时期进行类型检查,因此在一个运行的应用中动态的创建接口没有什么作用。但是InterfaceMaker可以用来自动生成接口代码,为以后的开发做准备。
方法代理,个人认为作用不太大,这里仅举例。
public class MethodDelegateDemo {
interface MethodDelegateInterface {
String getValueFromDelegate();
}
static class Delegate {
private String value;
public String getValue() {
return value;
}
public Delegate setValue(String value) {
this.value = value;
return this;
}
}
public static void main(String[] args) throws Exception {
Delegate delegate = new Delegate();
delegate.setValue("throwable");
MethodDelegate methodDelegate = MethodDelegate.create(delegate, "getValue", MethodDelegateInterface.class);
MethodDelegateInterface delegateInterface = (MethodDelegateInterface) methodDelegate;
System.out.println(delegateInterface.getValueFromDelegate());
}
}
输出结果:
throwable
多重代理,个人认为作用不太大,这里仅举例。
public class MulticastDelegateDemo {
public interface DelegateProvider {
void setValue(String value);
}
static class MulticastBean implements DelegateProvider {
private String value;
@Override
public void setValue(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
public static void main(String[] args) throws Exception {
MulticastDelegate multicastDelegate = MulticastDelegate.create(DelegateProvider.class);
MulticastBean first = new MulticastBean();
MulticastBean second = new MulticastBean();
multicastDelegate = multicastDelegate.add(first);
multicastDelegate = multicastDelegate.add(second);
DelegateProvider provider = (DelegateProvider) multicastDelegate;
provider.setValue("throwable");
System.out.println(first.getValue());
System.out.println(second.getValue());
}
}
输出结果:
throwable
throwable
构造器代理,个人认为作用不太大,这里仅举例。
public class ConstructorDelegateDemo {
public interface ConstructorInterface {
Object newInstance(String value);
}
static class ConstructorImpl {
private String value;
public ConstructorImpl(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public ConstructorImpl setValue(String value) {
this.value = value;
return this;
}
}
public static void main(String[] args) throws Exception {
ConstructorInterface constructorInterface =
(ConstructorInterface) ConstructorDelegate.create(ConstructorImpl.class, ConstructorInterface.class);
ConstructorImpl constructorImpl = (ConstructorImpl) constructorInterface.newInstance("throwable");
System.out.println(ConstructorImpl.class.isAssignableFrom(constructorImpl.getClass()));
System.out.println(constructorImpl.getValue());
}
}
输出结果:
true
throwable
并行排序器,能够对多个数组同时进行排序,目前实现的算法有归并排序(mergeSort)和快速排序(quickSort),查看源码的时候发现Float和Double类的比较直接用大于或者小于,有可能造成这两个类型的数据排序不准确(应该使用Float或Double的compare方法进行比较)。
public class ParallelSorterDemo {
public static void main(String[] args) throws Exception {
Integer[][] array = new Integer[][]{
{4, 3, 9, 0},
{2, 1, 6, 0}
};
ParallelSorter.create(array).quickSort(0);
for (Integer[] row : array) {
System.out.println(Arrays.toString(row));
}
}
}
输出结果:
[0, 3, 4, 9]
[0, 1, 2, 6]
FastClass就是对Class对象进行特定的处理,认知上可以理解为索引类,比如通过数组保存method引用,因此FastClass引出了一个index下标的新概念,比如getIndex(String name, Class[] parameterTypes)就是以前的获取method的方法。通过数组存储method,constructor等class信息,从而将原先的反射调用,转化为class.index的直接调用以提高效率,从而体现所谓的FastClass。
public class FastClassDemo {
public static void main(String[] args) throws Exception {
FastClass fastClass = FastClass.create(SampleClass.class);
FastMethod fastMethod = fastClass.getMethod("sayHello", new Class[]{String.class});
SampleClass sampleClass = new SampleClass();
System.out.println(fastMethod.invoke(sampleClass, new Object[]{"throwable"}));
System.out.println(fastMethod.getIndex());
}
}
输出结果:
throwable say hello!
0
实际上,在接口或者代理类的方法比较少的时候,使用FastClass进行方法调用有可能比原生反射方法调用Method#invoke()高,但是实际还是需要进行测试和分析,不能盲目一概而论。
本文简单分析了一下CGLIB中的常用API,其实在实现AOP、动态代理和反射调用的时候,最常用的是字节码增强器Enhancer、回调(Callback)以及快类(FastClass),掌握它们的使用方式有利于进行AOP编程以及反射性能创新性提升。
我已经设置了 Azure API 管理服务,并在自定义域上配置了它。在 Azure 门户中 API 管理服务的配置部分下,我设置了以下内容: 因为这是一个客户端系统,我必须屏蔽细节,但以下是基础知识:
我是一名习惯 React Native 的新程序员。我最近开始学习 Fetch API 及其工作原理。我的问题是,我找不到人们使用 API key 在他们的获取语句中访问信息的示例(我很难清楚地表达有
这里有很多关于 API 是什么的东西,但是我找不到我需要的关于插件 API 和类库 API 之间的区别。反正我不明白。 在 Documenting APIs 一书中,我读到:插件 API 和类库 AP
关闭。这个问题不满足Stack Overflow guidelines .它目前不接受答案。 想改善这个问题吗?更新问题,使其成为 on-topic对于堆栈溢出。 7年前关闭。 Improve thi
我正在尝试找出设计以下场景的最佳方法。 假设我已经有了一个 REST API 实现,它将从不同的供应商那里获取书籍并将它们返回给我自己的客户端。 每个供应商都提供单独的 API 来向其消费者提供图书。
请有人向我解释如何使用 api key 以及它有什么用处。 我对此进行了很多搜索,但得到了不同且相互矛盾的答案。有人说 API key 是保密的,它从不作为通信的一部分发送,而其他人则将它发送给客户端
关闭。这个问题是opinion-based .它目前不接受答案。 想改进这个问题?更新问题,以便 editing this post 可以用事实和引用来回答它. 4年前关闭。 Improve this
谁能告诉我为什么 WSo2 API 管理器不进行身份验证?我已经设置了两个 WSo2 API Manager 1.8.0 实例并创建了一个 api。它作为原型(prototype) api 工作正常。
我在学习 DSL 的过程中遇到了 Fluent API。 我在流利的 API 上搜索了很多……我可以得出的基本结论是,流利的 API 使用方法链来使代码流利。 但我无法理解——在面向对象的语言中,我们
基本上,我感兴趣的是在多个区域设置 WSO2 API 管理器;例如亚洲、美国和欧洲。一些 API 将部署在每个区域的数据中心内,而其他 API 将仅部署在特定区域内。 理想情况下,我想要的是一个单一的
我正在构建自己的 API,供以下用户使用: 1) 安卓应用 2) 桌面应用 我的网址之一是:http://api.chatapp.info/order_api/files/getbeers.php我的
我需要向所有用户显示我的站点的分析,但使用 OAuth 它显示为登录用户配置的站点的分析。如何使用嵌入 API 实现仪表板但仅显示我的网站分析? 我能想到的最好的可能性是使用 API key 而不是客
我正在研究大公司如何管理其公共(public) API。我想到的是拥有成熟 API 的公司,例如 Google、Facebook、Twitter 和 Amazon。 这些公司向公众公开了许多不同的 A
在定义客户可访问的 API 时,以下是首选的行业惯例: a) 定义一组显式 API 方法,每个方法都有非常狭窄和特定的目的,例如: SetUserName SetUserAge Se
这在本地 deserver 和部署时都会发生。我成功地能够通过留言簿教程使用 API 资源管理器,但现在我已经创建了自己的项目并尝试访问我编写的第一个 API,它从未出现过。搜索栏旁边的黄色“正在加载
我正在尝试使用 http://ip-api.com/ api通过我的ip地址获取经度和纬度。当我访问 http://ip-api.com/json从我的浏览器或使用 curl,它以 json 格式返回
这里的典型示例是 Twitter 的 API。我从概念上理解 REST API 的工作原理,本质上它只是针对您的特定请求向他们的服务器查询,然后您会在其中收到响应(JSON、XML 等),很棒。 但是
我能想到的最好的标题,但要澄清的是,情况是这样的: 我正在开发一种类似短 url 的服务,该服务允许用户使用他们的 Twitter 帐户“登录”并发布内容。现在这项服务可以包含在 Tweetdeck
我正在设计用于管理评论和讨论线程的 API 方案。我想有一个点 /discussions/:discussionId 当您GET 时,它会返回一组评论和一些元数据。评论也许可以单独访问 /discus
关闭。这个问题需要更多focused .它目前不接受答案。 想改进这个问题吗? 更新问题,使其只关注一个问题 editing this post . 关闭去年。 Improve this quest
我是一名优秀的程序员,十分优秀!