Browse Source

Merge remote-tracking branch 'origin/master'

pull/772/merge
Stephane Nicoll 11 years ago
parent
commit
fac639971a
  1. 12
      spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java
  2. 8
      spring-beans/src/test/java/org/springframework/beans/factory/FactoryBeanTests.java
  3. 2
      spring-beans/src/test/resources/org/springframework/beans/factory/FactoryBeanTests-withAutowiring.xml
  4. 7
      spring-context/src/main/java/org/springframework/context/ApplicationEventPublisher.java
  5. 3
      spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassEnhancer.java
  6. 44
      spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java
  7. 44
      spring-context/src/test/java/org/springframework/context/event/ApplicationContextEventTests.java

12
spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java

@ -1451,9 +1451,15 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp @@ -1451,9 +1451,15 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
return getTypeForFactoryBean(factoryBean);
}
catch (BeanCreationException ex) {
// Can only happen when getting a FactoryBean.
if (logger.isWarnEnabled()) {
logger.warn("Bean creation exception on FactoryBean type check: " + ex);
if (ex instanceof BeanCurrentlyInCreationException) {
if (logger.isDebugEnabled()) {
logger.debug("Bean currently in creation on FactoryBean type check: " + ex);
}
}
else {
if (logger.isWarnEnabled()) {
logger.warn("Bean creation exception on FactoryBean type check: " + ex);
}
}
onSuppressedException(ex);
return null;

8
spring-beans/src/test/java/org/springframework/beans/factory/FactoryBeanTests.java

@ -38,7 +38,7 @@ import static org.springframework.tests.TestResourceUtils.*; @@ -38,7 +38,7 @@ import static org.springframework.tests.TestResourceUtils.*;
* @author Juergen Hoeller
* @author Chris Beams
*/
public final class FactoryBeanTests {
public class FactoryBeanTests {
private static final Class<?> CLASS = FactoryBeanTests.class;
private static final Resource RETURNS_NULL_CONTEXT = qualifiedResource(CLASS, "returnsNull.xml");
@ -63,10 +63,13 @@ public final class FactoryBeanTests { @@ -63,10 +63,13 @@ public final class FactoryBeanTests {
BeanFactoryPostProcessor ppc = (BeanFactoryPostProcessor) factory.getBean("propertyPlaceholderConfigurer");
ppc.postProcessBeanFactory(factory);
assertNull(factory.getType("betaFactory"));
Alpha alpha = (Alpha) factory.getBean("alpha");
Beta beta = (Beta) factory.getBean("beta");
Gamma gamma = (Gamma) factory.getBean("gamma");
Gamma gamma2 = (Gamma) factory.getBean("gammaFactory");
assertSame(beta, alpha.getBeta());
assertSame(gamma, beta.getGamma());
assertSame(gamma2, beta.getGamma());
@ -194,6 +197,9 @@ public final class FactoryBeanTests { @@ -194,6 +197,9 @@ public final class FactoryBeanTests {
@Component
public static class BetaFactoryBean implements FactoryBean<Object> {
public BetaFactoryBean(Alpha alpha) {
}
private Beta beta;
public void setBeta(Beta beta) {

2
spring-beans/src/test/resources/org/springframework/beans/factory/FactoryBeanTests-withAutowiring.xml

@ -11,7 +11,7 @@ @@ -11,7 +11,7 @@
<bean id="gamma" class="org.springframework.beans.factory.FactoryBeanTests$Gamma"/>
<bean id="betaFactory" class="org.springframework.beans.factory.FactoryBeanTests$BetaFactoryBean">
<bean id="betaFactory" class="org.springframework.beans.factory.FactoryBeanTests$BetaFactoryBean" autowire="constructor">
<property name="beta" ref="beta"/>
</bean>

7
spring-context/src/main/java/org/springframework/context/ApplicationEventPublisher.java

@ -18,7 +18,7 @@ package org.springframework.context; @@ -18,7 +18,7 @@ package org.springframework.context;
/**
* Interface that encapsulates event publication functionality.
* Serves as super-interface for ApplicationContext.
* Serves as super-interface for {@link ApplicationContext}.
*
* @author Juergen Hoeller
* @author Stephane Nicoll
@ -42,9 +42,10 @@ public interface ApplicationEventPublisher { @@ -42,9 +42,10 @@ public interface ApplicationEventPublisher {
/**
* Notify all <strong>matching</strong> listeners registered with this
* application of an event.
* <p>If the specified {@code event} is not an {@link ApplicationEvent}, it
* is wrapped in a {@code GenericApplicationEvent}.
* <p>If the specified {@code event} is not an {@link ApplicationEvent},
* it is wrapped in a {@link PayloadApplicationEvent}.
* @param event the event to publish
* @since 4.2
* @see PayloadApplicationEvent
*/
void publishEvent(Object event);

3
spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassEnhancer.java

@ -46,6 +46,7 @@ import org.springframework.cglib.transform.ClassEmitterTransformer; @@ -46,6 +46,7 @@ import org.springframework.cglib.transform.ClassEmitterTransformer;
import org.springframework.cglib.transform.TransformingClassGenerator;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
@ -322,7 +323,7 @@ class ConfigurationClassEnhancer { @@ -322,7 +323,7 @@ class ConfigurationClassEnhancer {
}
Object beanInstance = (!ObjectUtils.isEmpty(beanMethodArgs) ?
beanFactory.getBean(beanName, beanMethodArgs) : beanFactory.getBean(beanName));
if (beanInstance != null && !beanMethod.getReturnType().isInstance(beanInstance)) {
if (beanInstance != null && !ClassUtils.isAssignableValue(beanMethod.getReturnType(), beanInstance)) {
String msg = String.format("@Bean method %s.%s called as a bean reference " +
"for type [%s] but overridden by non-compatible bean instance of type [%s].",
beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName(),

44
spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java

@ -165,6 +165,9 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader @@ -165,6 +165,9 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
/** Parent context */
private ApplicationContext parent;
/** Environment used by this context */
private ConfigurableEnvironment environment;
/** BeanFactoryPostProcessors to apply on refresh */
private final List<BeanFactoryPostProcessor> beanFactoryPostProcessors =
new ArrayList<BeanFactoryPostProcessor>();
@ -197,10 +200,10 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader @@ -197,10 +200,10 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
private ApplicationEventMulticaster applicationEventMulticaster;
/** Statically specified listeners */
private Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<ApplicationListener<?>>();
private final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<ApplicationListener<?>>();
/** Environment used by this context; initialized by {@link #createEnvironment()} */
private ConfigurableEnvironment environment;
/** ApplicationEvents published early */
private Set<ApplicationEvent> earlyApplicationEvents;
/**
@ -340,7 +343,9 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader @@ -340,7 +343,9 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
if (logger.isTraceEnabled()) {
logger.trace("Publishing event in " + getDisplayName() + ": " + event);
}
final ApplicationEvent applicationEvent;
// Decorate event as an ApplicationEvent if necessary
ApplicationEvent applicationEvent;
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
}
@ -350,7 +355,16 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader @@ -350,7 +355,16 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
eventType = ResolvableType.forClassWithGenerics(PayloadApplicationEvent.class, event.getClass());
}
}
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
// Multicast right now if possible - or lazily once the multicaster is initialized
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
}
else {
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}
// Publish event via parent context as well...
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
@ -379,7 +393,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader @@ -379,7 +393,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
* @return the internal LifecycleProcessor (never {@code null})
* @throws IllegalStateException if the context has not been initialized yet
*/
LifecycleProcessor getLifecycleProcessor() {
LifecycleProcessor getLifecycleProcessor() throws IllegalStateException {
if (this.lifecycleProcessor == null) {
throw new IllegalStateException("LifecycleProcessor not initialized - " +
"call 'refresh' before invoking lifecycle methods via the context: " + this);
@ -543,6 +557,10 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader @@ -543,6 +557,10 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
// Validate that all properties marked as required are resolvable
// see ConfigurablePropertyResolver#setRequiredProperties
getEnvironment().validateRequiredProperties();
// Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available...
this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
}
/**
@ -748,11 +766,21 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader @@ -748,11 +766,21 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let post-processors apply to them!
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String lisName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(lisName);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
// Publish early application events now that we finally have a multicaster...
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}

44
spring-context/src/test/java/org/springframework/context/event/ApplicationContextEventTests.java

@ -24,15 +24,20 @@ import org.aopalliance.intercept.MethodInvocation; @@ -24,15 +24,20 @@ import org.aopalliance.intercept.MethodInvocation;
import org.junit.Test;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.BeanThatBroadcasts;
import org.springframework.context.BeanThatListens;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.context.support.StaticApplicationContext;
import org.springframework.context.support.StaticMessageSource;
import org.springframework.core.Ordered;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.Order;
@ -48,6 +53,7 @@ import static org.mockito.BDDMockito.*; @@ -48,6 +53,7 @@ import static org.mockito.BDDMockito.*;
* @author Alef Arendsen
* @author Rick Evans
* @author Stephane Nicoll
* @author Juergen Hoeller
*/
public class ApplicationContextEventTests extends AbstractApplicationEventListenerTests {
@ -337,6 +343,21 @@ public class ApplicationContextEventTests extends AbstractApplicationEventListen @@ -337,6 +343,21 @@ public class ApplicationContextEventTests extends AbstractApplicationEventListen
context.close();
}
@Test
public void beanPostProcessorPublishesEvents() {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBeanDefinition("listener", new RootBeanDefinition(BeanThatListens.class));
context.registerBeanDefinition("messageSource", new RootBeanDefinition(StaticMessageSource.class));
context.registerBeanDefinition("postProcessor", new RootBeanDefinition(EventPublishingBeanPostProcessor.class));
context.refresh();
context.publishEvent(new MyEvent(this));
BeanThatListens listener = context.getBean(BeanThatListens.class);
assertEquals(4, listener.getEventCount());
context.close();
}
@SuppressWarnings("serial")
public static class MyEvent extends ApplicationEvent {
@ -410,6 +431,7 @@ public class ApplicationContextEventTests extends AbstractApplicationEventListen @@ -410,6 +431,7 @@ public class ApplicationContextEventTests extends AbstractApplicationEventListen
}
}
@Order(5)
public static class MyOrderedListener3 implements ApplicationListener<ApplicationEvent> {
@ -422,6 +444,7 @@ public class ApplicationContextEventTests extends AbstractApplicationEventListen @@ -422,6 +444,7 @@ public class ApplicationContextEventTests extends AbstractApplicationEventListen
}
@Order(50)
public static class MyOrderedListener4 implements ApplicationListener<MyEvent> {
@ -437,4 +460,25 @@ public class ApplicationContextEventTests extends AbstractApplicationEventListen @@ -437,4 +460,25 @@ public class ApplicationContextEventTests extends AbstractApplicationEventListen
}
}
public static class EventPublishingBeanPostProcessor implements BeanPostProcessor, ApplicationContextAware {
private ApplicationContext applicationContext;
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
this.applicationContext.publishEvent(new MyEvent(this));
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
}

Loading…
Cancel
Save