在前面中,我们知道如果一个bean需要被加载,首先需要获取资源的位置,然后根据资源位置获取xml文件,然后将其变成document,然后根据document对元素进行解析,然后放入beanDefintionMap中,然后通过getBean获取bean,而这个过程是bean加载的过程。而这里关注的重点是doGetBean。
public class BeanFactoryTest {
public static void main(String[] args) {
//获取xml资源
Resource resource = new ClassPathResource("spring-factory.xml");
//获取bean工厂
BeanFactory beanFactory = new XmlBeanFactory(resource);
//获取bean
Product car1 = (Product) beanFactory.getBean("car");
Product car2 = (Product) beanFactory.getBean("car");
car1.show();
System.out.println(car1 == car2);
}
}
在getBean中,在这个过程中,首先会将bean进行转换,然后执行获取单例对象操作,然后执行后续操作。而获取单例的过程是值得我们学习的。
AbstractBeanFactory#doGetBean
Object sharedInstance = getSingleton(beanName);
获取单例对象:采用的是单例模式,这里采用双重校验double check。
/**
* Return the (raw) singleton object registered under the given name.
* <p>Checks already instantiated singletons and also allows for an early
* reference to a currently created singleton (resolving a circular reference).
* @param beanName the name of the bean to look for
* @param allowEarlyReference whether early references should be created or not
* @return the registered singleton object, or {@code null} if none found
*/
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//获取单例bean对象
Object singletonObject = this.singletonObjects.get(beanName);
//如果单例bean对象为空,同时当前被创建对象,则首先对单例对象进行锁定,进行再一次判空,然后进行获取
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
单例模式的创建过程:首先定义类,在类的基础上定义对象,提供空参构造函数,然后基于对象创建一个方法获取单例对象,而为了防止获取单例对象出现并发问题,需要对获取的单例对象进行double check,同时定义的对象为了防止出现指令重排的问题,需要加内存屏障,因此可以加volitale进行修饰。
常见的单例模式中:
饿汉式:
/**
* 获取单例对象
*/
public class Singleton {
//创建对象
private static Singleton instance = new Singleton();
//提供空参构造
private Singleton() {
}
//返回对象
public static Singleton getInstance() {
return instance;
}
}
懒汉式:
/**
* 获取单例对象
*/
public class Singgleton {
//创建对象
private static Singgleton singleton = null;
//提供空参构造函数
private Singgleton(){};
//静态工厂方法
public static Singgleton getSingleton(){
if(singleton==null){
singleton = new Singgleton();
}
return singleton;
}
}
使用双重校验:
/**
* 创建单例对象 双重校验
*/
public class Singleton1 {
//定义对象
private static Singleton1 singleton = null;
//提供空参构造
private Singleton1(){}
//使用双重校验锁 double check,返回创建对象
public static Singleton1 getSingleton(){
if(singleton==null){
synchronized (Singleton1.class){
if(singleton==null) {
singleton = new Singleton1();
}
}
}
return singleton;
}
}
但是采用双重校验还是会存在指令重排的问题,而解决指令重排的问题,则可以采用内存屏障解决这个问题,此时可以借助volitale来解决这个问题,因为内存屏障是在读和写中加入屏障,从而避免其指令重排,从而解决指令重排的问题。
public class Single {
private static volatile Single singleStance = null;
private Single(){
System.out.println("Single 的构造方法被执行了!!!");
}
//DCL: double check lock 双端检索机制
public static Single getSingleStance() {
if (singleStance == null) {
synchronized (Single.class) {
if (singleStance == null) {
singleStance = new Single();
}
}
}
return singleStance;
}
}
除了上面的,还有一个effective java作者推荐的单例模式,枚举:
public class Singleton{
// 私有构造函数
private Singleton() {}
public static Singleton getInstance() {
return Singleton.INSTANCE.getInstance();
}
private enum Singleton {
INSTANCE;
private Singleton singleton;
// JVM保证这个方法绝对只调用一次
Singleton() {
singleton = new Singleton();
}
public Singleton getInstance() {
return singleton;
}
}
}
单例模式的使用场景:
1.Web应用的配置对象的读取,一般也应用单例模式,这个是由于配置文件是共享的资源。
2.应用程序的日志应用,一般都何用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加。
3.数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源
4.多线程的线程池的设计一般也是采用单例模式,这是由于线程池要方便对池中的线程进行控制
5.spring的bean默认也是单例模式,springMVC是单例模式
6.mysql,redis等的连接对象使用单例模式
当然除了我们看到的上面的获取单例的方法,其实在spring的源码中,我们还可以看到一个增强版的获取单例的方法,这个getSingleton方法除了dubbo check之外,还在其前后做了后置处理的增强:
/**
* Return the (raw) singleton object registered under the given name,
* creating and registering a new one if none registered yet.
* @param beanName the name of the bean
* @param singletonFactory the ObjectFactory to lazily create the singleton
* with, if necessary
* @return the registered singleton object
*/
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
//单例对象创建前的操作
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
// Has the singleton object implicitly appeared in the meantime ->
// if yes, proceed with it since the exception indicates that state.
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw ex;
}
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
//单例对象创建后的处理
afterSingletonCreation(beanName);
}
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
单例模式的使用场景可以在dubbo中可以看到应用:
ServiceClassPostProcessor#resolveBeanNameGenerator
/**
* It'd better to use BeanNameGenerator instance that should reference
* {@link ConfigurationClassPostProcessor#componentScanBeanNameGenerator},
* thus it maybe a potential problem on bean name generation.
*
* @param registry {@link BeanDefinitionRegistry}
* @return {@link BeanNameGenerator} instance
* @see SingletonBeanRegistry
* @see AnnotationConfigUtils#CONFIGURATION_BEAN_NAME_GENERATOR
* @see ConfigurationClassPostProcessor#processConfigBeanDefinitions
* @since 2.5.8
*/
private BeanNameGenerator resolveBeanNameGenerator(BeanDefinitionRegistry registry) {
BeanNameGenerator beanNameGenerator = null;
if (registry instanceof SingletonBeanRegistry) {
SingletonBeanRegistry singletonBeanRegistry = SingletonBeanRegistry.class.cast(registry);
beanNameGenerator = (BeanNameGenerator) singletonBeanRegistry.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
}
if (beanNameGenerator == null) {
if (logger.isInfoEnabled()) {
logger.info("BeanNameGenerator bean can't be found in BeanFactory with name ["
+ CONFIGURATION_BEAN_NAME_GENERATOR + "]");
logger.info("BeanNameGenerator will be a instance of " +
AnnotationBeanNameGenerator.class.getName() +
" , it maybe a potential problem on bean name generation.");
}
beanNameGenerator = new AnnotationBeanNameGenerator();
}
return beanNameGenerator;
}
对于设计模式中的应用,前面我们看到的观察者模式同样也在dubbo中得到了使用。在之前的dubbo版本中,使用的是自定义标签的方式进行的bean注入。
在dubbo的2.7版本中,我们可以看到dubbo的版本是基于spring的事件进行bean的初始化操作的,采用的观察者模式实现的:applicationEventPublisher.publishEvent(exportEvent)。
/**
* ServiceFactoryBean
*
* @export
*/
public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean, DisposableBean,
ApplicationContextAware, BeanNameAware, ApplicationEventPublisherAware {
private static final long serialVersionUID = 213195494150089726L;
private final transient Service service;
private transient ApplicationContext applicationContext;
private transient String beanName;
private ApplicationEventPublisher applicationEventPublisher;
public ServiceBean() {
super();
this.service = null;
}
public ServiceBean(Service service) {
super(service);
this.service = service;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
SpringExtensionFactory.addApplicationContext(applicationContext);
}
@Override
public void setBeanName(String name) {
this.beanName = name;
}
/**
* Gets associated {@link Service}
*
* @return associated {@link Service}
*/
public Service getService() {
return service;
}
@Override
public void afterPropertiesSet() throws Exception {
if (StringUtils.isEmpty(getPath())) {
if (StringUtils.isNotEmpty(getInterface())) {
setPath(getInterface());
}
}
}
/**
* Get the name of {@link ServiceBean}
*
* @return {@link ServiceBean}'s name
* @since 2.6.5
*/
@Parameter(excluded = true)
public String getBeanName() {
return this.beanName;
}
/**
* @since 2.6.5
*/
@Override
public void exported() {
super.exported();
// Publish ServiceBeanExportedEvent
publishExportEvent();
}
/**
* @since 2.6.5
*/
private void publishExportEvent() {
ServiceBeanExportedEvent exportEvent = new ServiceBeanExportedEvent(this);
applicationEventPublisher.publishEvent(exportEvent);
}
@Override
public void destroy() throws Exception {
// no need to call unexport() here, see
// org.apache.dubbo.config.spring.extension.SpringExtensionFactory.ShutdownHookListener
}
// merged from dubbox
@Override
protected Class getServiceClass(T ref) {
if (AopUtils.isAopProxy(ref)) {
return AopUtils.getTargetClass(ref);
}
return super.getServiceClass(ref);
}
/**
* @param applicationEventPublisher
* @since 2.6.5
*/
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
}