一、背景
最近在研读Spring的官方文档,当在对照Spring源码时,发现了Objenesis的字样,于是谈谈究竟:
package org.springframework.aop.framework;
import java.lang.reflect.Constructor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.Factory;
import org.springframework.objenesis.SpringObjenesis;
import org.springframework.util.ReflectionUtils;
/**
* Objenesis-based extension of {@link CglibAopProxy} to create proxy instances
* without invoking the constructor of the class. Used by default as of Spring 4.
*
* @author Oliver Gierke
* @author Juergen Hoeller
* @since 4.0
*/
@SuppressWarnings("serial")
class ObjenesisCglibAopProxy extends CglibAopProxy {
private static final Log logger = LogFactory.getLog(ObjenesisCglibAopProxy.class);
private static final SpringObjenesis objenesis = new SpringObjenesis();
/**
* Create a new ObjenesisCglibAopProxy for the given AOP configuration.
* @param config the AOP configuration as AdvisedSupport object
*/
public ObjenesisCglibAopProxy(AdvisedSupport config) {
super(config);
}
@Override
protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
Class<?> proxyClass = enhancer.createClass();
Object proxyInstance = null;
if (objenesis.isWorthTrying()) {
try {
proxyInstance = objenesis.newInstance(proxyClass, enhancer.getUseCache());
}
catch (Throwable ex) {
logger.debug("Unable to instantiate proxy using Objenesis, " +
"falling back to regular proxy construction", ex);
}
}
if (proxyInstance == null) {
// Regular instantiation via default constructor...
try {
Constructor<?> ctor = (this.constructorArgs != null ?
proxyClass.getDeclaredConstructor(this.constructorArgTypes) :
proxyClass.getDeclaredConstructor());
ReflectionUtils.makeAccessible(ctor);
proxyInstance = (this.constructorArgs != null ?
ctor.newInstance(this.constructorArgs) : ctor.newInstance());
}
catch (Throwable ex) {
throw new AopConfigException("Unable to instantiate proxy using Objenesis, " +
"and regular proxy instantiation via default constructor fails as well", ex);
}
}
((Factory) proxyInstance).setCallbacks(callbacks);
return proxyInstance;
}
}
二、objenesis简介
1、简介
objenesis是一个小型java类库用来实例化一个特定class的对象。
2、使用场合
Java已经支持使用Class.newInstance()动态实例化类的实例。但是类必须拥有一个合适的构造器。有很多场景下不能使用这种方式实例化类,比如:
-
构造器需要参数
-
构造器有side effects
-
构造器会抛异常
因此,在类库中经常会有类必须拥有一个默认构造器的限制。Objenesis通过绕开对象实例构造器来克服这个限制。
3、典型使用
实例化一个对象而不调用构造器是一个特殊的任务,然而在一些特定的场合是有用的:
-
序列化,远程调用和持久化 -对象需要实例化并存储为到一个特殊的状态,而没有调用代码。
-
代理,AOP库和Mock对象 -类可以被子类继承而子类不用担心父类的构造器
-
容器框架 -对象可以以非标准的方式被动态实例化。
三、objenesis示例
1、在pom.xml中引入依赖
<!-- https://mvnrepository.com/artifact/org.objenesis/objenesis -->
<dependency>
<groupId>org.objenesis</groupId>
<artifactId>objenesis</artifactId>
<version>3.0.1</version>
</dependency>
2、示例代码如下
package io.gitee.inrgihc.objenesis;
import org.objenesis.Objenesis;
import org.objenesis.ObjenesisStd;
import org.objenesis.instantiator.ObjectInstantiator;
class Person {
{
System.out.println("In Person instance function");
}
public Person() {
System.out.println("In Person constructor function");
throw new RuntimeException("constructor can not used!");
}
public void show() {
System.out.println("Person show() function called!" + this.hashCode());
}
}
public class Application {
public static void main(String[] args) {
Objenesis objenesis = new ObjenesisStd();
ObjectInstantiator<Person> instantiator = objenesis.getInstantiatorOf(Person.class);
Person p1 = instantiator.newInstance();
p1.show();
Person p2 = instantiator.newInstance();
p2.show();
}
}
运行结果:
Person show() function called!312714112
Person show() function called!692404036