-
Notifications
You must be signed in to change notification settings - Fork 85
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #13 from mercyblitz/1.0.4
1.0.4
- Loading branch information
Showing
19 changed files
with
751 additions
and
166 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
59 changes: 59 additions & 0 deletions
59
...n/java/com/alibaba/spring/beans/factory/annotation/ConfigurationBeanBindingsRegister.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
/* | ||
* Licensed to the Apache Software Foundation (ASF) under one or more | ||
* contributor license agreements. See the NOTICE file distributed with | ||
* this work for additional information regarding copyright ownership. | ||
* The ASF licenses this file to You under the Apache License, Version 2.0 | ||
* (the "License"); you may not use this file except in compliance with | ||
* the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package com.alibaba.spring.beans.factory.annotation; | ||
|
||
import org.springframework.beans.factory.support.BeanDefinitionRegistry; | ||
import org.springframework.context.EnvironmentAware; | ||
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; | ||
import org.springframework.core.annotation.AnnotationAttributes; | ||
import org.springframework.core.env.ConfigurableEnvironment; | ||
import org.springframework.core.env.Environment; | ||
import org.springframework.core.type.AnnotationMetadata; | ||
import org.springframework.util.Assert; | ||
|
||
/** | ||
* The {@link ImportBeanDefinitionRegistrar Registrar class} for {@link EnableConfigurationBeanBindings} | ||
* | ||
* @since 1.0.4 | ||
*/ | ||
public class ConfigurationBeanBindingsRegister implements ImportBeanDefinitionRegistrar, EnvironmentAware { | ||
|
||
private ConfigurableEnvironment environment; | ||
|
||
@Override | ||
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { | ||
|
||
AnnotationAttributes attributes = AnnotationAttributes.fromMap( | ||
importingClassMetadata.getAnnotationAttributes(EnableConfigurationBeanBindings.class.getName())); | ||
|
||
AnnotationAttributes[] annotationAttributes = attributes.getAnnotationArray("value"); | ||
|
||
ConfigurationBeanBindingRegistrar registrar = new ConfigurationBeanBindingRegistrar(); | ||
|
||
registrar.setEnvironment(environment); | ||
|
||
for (AnnotationAttributes element : annotationAttributes) { | ||
registrar.registerConfigurationBeanDefinitions(element, registry); | ||
} | ||
} | ||
|
||
@Override | ||
public void setEnvironment(Environment environment) { | ||
Assert.isInstanceOf(ConfigurableEnvironment.class, environment); | ||
this.environment = (ConfigurableEnvironment) environment; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
42 changes: 42 additions & 0 deletions
42
...ain/java/com/alibaba/spring/beans/factory/annotation/EnableConfigurationBeanBindings.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
/* | ||
* Licensed to the Apache Software Foundation (ASF) under one or more | ||
* contributor license agreements. See the NOTICE file distributed with | ||
* this work for additional information regarding copyright ownership. | ||
* The ASF licenses this file to You under the Apache License, Version 2.0 | ||
* (the "License"); you may not use this file except in compliance with | ||
* the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package com.alibaba.spring.beans.factory.annotation; | ||
|
||
import org.springframework.context.annotation.Import; | ||
|
||
import java.lang.annotation.Documented; | ||
import java.lang.annotation.ElementType; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
import java.lang.annotation.Target; | ||
|
||
/** | ||
* The annotation composes the multiple {@link EnableConfigurationBeanBinding EnableConfigurationBeanBindings} | ||
* | ||
* @since 1.0.4 | ||
*/ | ||
@Target({ElementType.TYPE}) | ||
@Retention(RetentionPolicy.RUNTIME) | ||
@Documented | ||
@Import(ConfigurationBeanBindingsRegister.class) | ||
public @interface EnableConfigurationBeanBindings { | ||
|
||
/** | ||
* @return the array of {@link EnableConfigurationBeanBinding EnableConfigurationBeanBindings} | ||
*/ | ||
EnableConfigurationBeanBinding[] value(); | ||
} |
178 changes: 178 additions & 0 deletions
178
src/main/java/com/alibaba/spring/context/event/DeferredApplicationEventPublisher.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
/* | ||
* Licensed to the Apache Software Foundation (ASF) under one or more | ||
* contributor license agreements. See the NOTICE file distributed with | ||
* this work for additional information regarding copyright ownership. | ||
* The ASF licenses this file to You under the Apache License, Version 2.0 | ||
* (the "License"); you may not use this file except in compliance with | ||
* the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package com.alibaba.spring.context.event; | ||
|
||
import org.springframework.context.ApplicationContext; | ||
import org.springframework.context.ApplicationEvent; | ||
import org.springframework.context.ApplicationEventPublisher; | ||
import org.springframework.context.ApplicationListener; | ||
import org.springframework.context.ConfigurableApplicationContext; | ||
import org.springframework.context.event.ApplicationEventMulticaster; | ||
import org.springframework.context.event.ContextRefreshedEvent; | ||
import org.springframework.context.support.AbstractApplicationContext; | ||
import org.springframework.util.ReflectionUtils; | ||
|
||
import java.lang.reflect.Method; | ||
import java.util.Iterator; | ||
import java.util.concurrent.ConcurrentLinkedQueue; | ||
|
||
import static org.springframework.util.Assert.notNull; | ||
import static org.springframework.util.ReflectionUtils.findField; | ||
import static org.springframework.util.ReflectionUtils.findMethod; | ||
|
||
/** | ||
* Before Spring Framework 4.2, {@link AbstractApplicationContext} is an implementation of {@link ApplicationEventPublisher} | ||
* can't handle the early {@link ApplicationEvent event} that is {@link #publishEvent(ApplicationEvent) published} | ||
* before {@link ApplicationEventMulticaster}'s initialization, in this scenario, {@link DeferredApplicationEventPublisher} | ||
* is introduced and used to resolve {@link #publishEvent(ApplicationEvent)} too early | ||
* to publish {@link ApplicationEvent} when {@link AbstractApplicationContext#initApplicationEventMulticaster() | ||
* Spring ApplicationContexts' ApplicationEventMulticaster} is not ready. | ||
* First, {@link DeferredApplicationEventPublisher} stores these early events temporarily, and then | ||
* {@link #replayDeferredEvents() re-publish} them on {@link ContextRefreshedEvent Application context is ready}. | ||
* <p> | ||
* In contrast, If current runtime is based on Spring Framework that {@link #supportsEarlyApplicationEvents() supports | ||
* early application events}, {@link DeferredApplicationEventPublisher} only delegates the | ||
* {@link ConfigurableApplicationContext Application Context} that was injected by | ||
* {@link #DeferredApplicationEventPublisher(ApplicationEventPublisher) constructor}. | ||
* | ||
* @author <a href="mailto:[email protected]">Mercy</a> | ||
* @since 1.0.4 | ||
*/ | ||
public class DeferredApplicationEventPublisher implements ApplicationEventPublisher, ApplicationListener<ContextRefreshedEvent> { | ||
|
||
/** | ||
* The field name of {@link AbstractApplicationContext#earlyApplicationEvents} | ||
*/ | ||
private static final String EARLY_APPLICATION_EVENTS_FIELD_NAME = "earlyApplicationEvents"; | ||
|
||
/** | ||
* The field name of {@link AbstractApplicationContext#applicationEventMulticaster} | ||
*/ | ||
private static final String APPLICATION_EVENT_MULTICASTER_FIELD_NAME = "applicationEventMulticaster"; | ||
|
||
/** | ||
* The method name of publishEvent(Object) | ||
*/ | ||
private static final String PUBLISH_EVENT_OBJECT_METHOD_NAME = "publishEvent"; | ||
|
||
/** | ||
* {@link ApplicationEventPublisher#publishEvent(Object)} method | ||
*/ | ||
private static final Method PUBLISH_EVENT_METHOD = detectPublishEventMethod(); | ||
|
||
private final ApplicationEventPublisher delegate; | ||
|
||
/** | ||
* May be null if the argument of {@link ApplicationEventPublisher} from constructor | ||
*/ | ||
private final ConfigurableApplicationContext context; | ||
|
||
private final ConcurrentLinkedQueue<ApplicationEvent> deferredEvents = new ConcurrentLinkedQueue<ApplicationEvent>(); | ||
|
||
private final boolean shouldDefer; | ||
|
||
/** | ||
* @param delegate {@link ApplicationEventPublisher} | ||
*/ | ||
public DeferredApplicationEventPublisher(ApplicationEventPublisher delegate) { | ||
notNull(delegate, "The ApplicationEventPublisher argument must not be null"); | ||
this.delegate = delegate; | ||
this.context = delegate instanceof ConfigurableApplicationContext ? (ConfigurableApplicationContext) delegate : null; | ||
if (this.context != null) { | ||
this.context.addApplicationListener(this); | ||
} | ||
this.shouldDefer = !supportsEarlyApplicationEvents() || !isInitializedApplicationEventMulticaster(); | ||
} | ||
|
||
protected boolean supportsPublishEventMethod() { | ||
return PUBLISH_EVENT_METHOD != null; | ||
} | ||
|
||
@Override | ||
public void publishEvent(ApplicationEvent event) { | ||
if (shouldDefer) { | ||
// before Spring 4.2 | ||
deferEvent(event); | ||
} else { | ||
doPublishEvent(event); | ||
} | ||
} | ||
|
||
private void doPublishEvent(ApplicationEvent event) { | ||
delegate.publishEvent(event); | ||
} | ||
|
||
private void deferEvent(ApplicationEvent event) { | ||
try { | ||
deferredEvents.add(event); | ||
} catch (Exception ignore) { | ||
deferredEvents.add(event); | ||
} | ||
} | ||
|
||
/** | ||
* Current method will not be invoked before Spring 4.2 | ||
* | ||
* @param event the {@link ApplicationEvent} or the payload of {@link ApplicationEvent event} | ||
*/ | ||
public void publishEvent(Object event) { | ||
if (supportsEarlyApplicationEvents() && supportsPublishEventMethod()) { | ||
// invoke by reflection to resolve the compilation issue | ||
ReflectionUtils.invokeMethod(PUBLISH_EVENT_METHOD, delegate, event); | ||
} else { // before Spring 4.2 | ||
// DO NOTHING, just resolve the compilation issue in Spring 4.2 and above | ||
} | ||
} | ||
|
||
@Override | ||
public void onApplicationEvent(ContextRefreshedEvent event) { | ||
|
||
if (supportsEarlyApplicationEvents()) { | ||
return; | ||
} | ||
|
||
ApplicationContext currentContext = event.getApplicationContext(); | ||
|
||
if (!currentContext.equals(delegate)) { | ||
// prevent multiple event multi-casts in hierarchical contexts | ||
return; | ||
} | ||
|
||
replayDeferredEvents(); | ||
} | ||
|
||
private void replayDeferredEvents() { | ||
Iterator<ApplicationEvent> iterator = deferredEvents.iterator(); | ||
while (iterator.hasNext()) { | ||
ApplicationEvent event = iterator.next(); | ||
doPublishEvent(event); | ||
iterator.remove(); // remove if published | ||
} | ||
} | ||
|
||
private boolean supportsEarlyApplicationEvents() { | ||
return context != null && findField(context.getClass(), EARLY_APPLICATION_EVENTS_FIELD_NAME) != null; | ||
} | ||
|
||
private boolean isInitializedApplicationEventMulticaster() { | ||
return context != null && findField(context.getClass(), APPLICATION_EVENT_MULTICASTER_FIELD_NAME) != null; | ||
} | ||
|
||
private static Method detectPublishEventMethod() { | ||
return findMethod(ApplicationEventPublisher.class, PUBLISH_EVENT_OBJECT_METHOD_NAME, Object.class); | ||
} | ||
} |
Oops, something went wrong.