Spring does not abort bootstrapping on bean initialization Error when component scanning is enabled? - spring

I have a web application with a spring configuration file. I have the following entry:
<bean id="flyway" class="xxx.FlywayTool" init-method="migrateOrFail"/>
The "flyway" bean is used to initialize and migrate the database.Now I have another bean defining the datasource the application should use:
<bean id="dataSource" class="..." depends-on="flyway">
this one depends on flyway to succeed.
Everything is working fine. Now, when the "flyway" bean throws an exception the bootstrapping of spring stops and the webapp startup is finished - all good.
Now i am starting to enable autowiring for certain components via:
<context:component-scan base-package="de.xxxxx.xxxxx" />
in some of the classes I depend on services which are also defined as beans in the xml configuration. and they I turn depend on the datasource mentioned above.
now the problem: as soon as I bootstrap the application now and "flyway" is throwing an exception the exception is swallowed by spring in the following section:
org.springframework.beans.factory.support.AbstractBeanFactory.getTypeForFactoryBean(String, RootBeanDefinition)
catch (BeanCreationException ex) {
// Can only happen when getting a FactoryBean.
if (logger.isDebugEnabled()) {
logger.debug("Ignoring bean creation exception on FactoryBean type check: " + ex);
}
onSuppressedException(ex);
return null;
}
and now spring tries, for every other dependend service (that depends on the datasource and therefore flyway) initialize all the beans which in turn results in the same procedure again and again.
This exceptional loop continues until spring is finished trying to instaniate every possible dependency instead of aborting after the first flyway error.
This strange behaviour only starts when I enable component scanning via
<context:component-scan ....
when this feature is disabled spring stops after the first flyway error happend. It also ends up in another class:
org.springframework.context.support.AbstractApplicationContext.refresh()
catch (BeansException ex) {
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
so this is the behaviour i would expect in the other case too.
our spring version: 3.0.6.RELEASE
this behaviour is also present with other classes throwing any runtime execption (not just flyway) is this a bug or expected behaviour?
any help highly appreciated
marcel

Put <context:component-scan... after your beans declaration in your XML file as nico_ekito said in comments.
Confirmed to work:
Marcel: wow, that seems to work. you reckon i should open a bug? or is this intended behaviour?

Related

spring-integration: SplitterFactoryBean may only be referenced once

I have a Spring project (not using Spring Boot, if that's relevant) that I'm trying to connect to a local database using the Postgres JDBC driver. (The local database is actually Yugabyte, but that should be fully compatible with the Postgres driver.)
When starting the application, I get this error message:
java.lang.IllegalArgumentException: An AbstractMessageProducingMessageHandler may only be referenced once (org.springframework.integration.config.SplitterFactoryBean#0) - use scope="prototype"
at org.springframework.util.Assert.isTrue(Assert.java:118)
at org.springframework.integration.config.AbstractStandardMessageHandlerFactoryBean.checkReuse(AbstractStandardMessageHandlerFactoryBean.java:168)
at org.springframework.integration.config.AbstractStandardMessageHandlerFactoryBean.createHandler(AbstractStandardMessageHandlerFactoryBean.java:137)
at org.springframework.integration.config.AbstractSimpleMessageHandlerFactoryBean.createHandlerInternal(AbstractSimpleMessageHandlerFactoryBean.java:186)
at org.springframework.integration.config.AbstractSimpleMessageHandlerFactoryBean.getObject(AbstractSimpleMessageHandlerFactoryBean.java:174)
at org.springframework.integration.config.AbstractSimpleMessageHandlerFactoryBean.getObject(AbstractSimpleMessageHandlerFactoryBean.java:59)
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:171)
... 52 more
I can't place this error at all. There is one similar question on Stack Overflow, but there the asker seems to actually know what they're doing and how this is related to spring integration. I, however, am not aware at all that I'm trying to 'reuse' anything. The referenced question also doesn't seem to be related to database configuration.
My setup/configuration is a bit involved, so I'll try to quote the parts that seem relevant.
I have a dao layer project that has the following gradle dependencies (among others):
implementation("org.springframework:spring-context:5.2.2.RELEASE")
implementation("org.springframework:spring-jdbc:5.2.2.RELEASE")
implementation("org.jooq:jooq-kotlin:3.14.11")
runtimeOnly("org.postgresql:postgresql:42.2.19.jre7")
In the same project, I have some configuration (in Kotlin):
#Configuration
open class Config {
#Bean
open fun jdbcTemplate(dataSource: DataSource): JdbcTemplate = JdbcTemplate(dataSource)
#Bean
open fun dslContext(): DSLContext = DefaultDSLContext(SQLDialect.POSTGRES)
#Configuration
#Profile("!unittest")
open inner class NonTestConfig {
#Bean
open fun dataSource(): DataSource {
return DriverManagerDataSource().apply {
// Hardcoded properties to be replaced by values from property file
setDriverClassName("org.postgresql.Driver")
url = "jdbc:postgresql://localhost:5433/demo"
username = "yugabyte"
password = "yugabyte"
}
}
}
}
(Notes: the DSLContext bean is used for JOOQL, included for completeness' sake. The inner class config is there because there is also a separate unit testing config for an embedded database - that one works fine!)
Now, the above project is used in my top-level project that contains the actual application. It's a maven runtime dependency there. I import the config class in this project's XML configuration, using this method:
<context:annotation-config />
<bean class="my.package.Config" />
Then trying to start the application produces the error message.
I figured out what the problem was, but I still don't know how it relates to a <splitter>.
The problem was that the Config class, apart from the database stuff, also included a bean to encrypt data. It turned out that this bean was also defined in another library used by the top-level project. Fixing this duplicate bean problem made the error go away.
I discovered this in a roundabout way: I included the dao project and its configuration in a different top-level project that uses Spring Boot. This led to a clear error message about the encryptor bean having two definitions.
If anyone can explain why the error message is so cryptic in the non-Boot case, that would be a nice complementary answer.

CXF Interceptor phases being skipped for missing phase declaration

Been working on this one for a bit and haven't had any luck.
I'm in the process of upgrading from Spring 3.2.9 to 4.2.6. My first step was upgrading to cxf-core 3.1.6, which I did with no issues to the app.
When upgrading all spring dependencies I am running into an issue with the interceptor setup though. Here's the basics:
Interceptor
public class MyInterceptor extends AbstractPhaseInterceptor<Message>{
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(MyInterceptor.class);
public MyInterceptor() {
super(Phase.PRE_INVOKE);
addAfter(HolderInInterceptor.class.getName());
}
#PostConstruct
public void display() {
logger.warn(this.getPhase());
}
#Override
public void handleMessage(Message message) throws Fault {
....
cxfContext.xml
<bean id="contentInInterceptor" class="com.MyInterceptor">
</bean>
<cxf:bus>
<cxf:inInterceptors>
<ref bean="contentInInterceptor"/>
</cxf:inInterceptors>
</cxf:bus>
as well as it being added in web.xml. When running I see the logged information showing the interceptor is created with a phase of pre-invoke (I added this to verify I'm not going crazy). But when calling the service, the PhaseInterceptor chain is skipping the interceptor for not declaring a phase:
Logs:
2016-05-31 16:08:28,208 [localhost-startStop-1] [] WARN
c.MyInterceptor - pre-invoke
2016-05-31 16:10:14,552
[http-bio-8080-exec-1] [] WARN o.a.c.p.PhaseInterceptorChain -
Skipping interceptor
com.MyInterceptor$$EnhancerBySpringCGLIB$$1afa70e1: Phase declaration
is missing.
This is intercepting a jaxws server call. Again, all I've changed that has caused the issues is updating to the latest version of Spring. It almost appears as though cxf is using a separate interceptor that was never generated from the bean.
EDIT
I believe I've found the issue, but again I'm not sure where the fix would be. Spring 4 proxy does not call the constructor twice when creating the proxy (i.e. it creates the raw bean using the constructor, but the CGLIB created proxy of the bean does not call the constructor). This causes the phase of the interceptor to be null.
I changed around my #PostContsruct on the class to confirm this:
#PostConstruct
public void display() {
logger.warn(this.getPhase());
MyInterceptor myInterceptor = (MyInterceptor) appContext.getBean("contentInInterceptor");
logger.warn("Bean phase is: " + myInterceptor.getPhase());
}
Logs show bean creation's phase versus proxy's phase:
2016-06-01 10:36:52,829 [localhost-startStop-1] [] WARN c.MyInterceptor - pre-invoke
2016-06-01 10:36:52,839 [localhost-startStop-1] [] WARN c.MyInterceptor - Bean phase is: null
Alright, I figured out a way around this for now, but it isn't the greatest implementation.
Basically what I ended up having to do was create an abstract class that implemented PhaseInterceptor and all of those implemented methods were set as abstract.
Then my interceptors extended from that class and had their own phase/id/before/after variables. It appears as though there may be an issue with Spring's bean proxy setup when variables are not available in the bean's direct class. At least that's what I'm finding in this case.
Again, not sure if it's the best solution, but this makes the interceptors work again.
You said that interceptor is intercepting jaxws server call. So my assumption is, it is outgoing call.
Phase.PRE_INVOKE is for incoming message. Use other phases like Phase.PRE_STREAM for outgoing message
For documentation of phases please see
http://cxf.apache.org/docs/interceptors.html

JerseyTest and Spring and creating a ServletContext

I'm working on migrating from Jersey 1.16 to Jersey 2.7. I have the application running and working, but I'm having trouble with the tests.
Some things to note:
The application uses Spring and is configured by a class, ApplicationConfiguration.class.
The application does not have a web.xml - the Jersey servlet and filters are configured programmatically.
I am using the jersey-spring3 library.
Related to using the jersey-spring3 library, I have to add a workaround to my onStartup method
// The following line is required to avoid having jersey-spring3 registering it's own Spring root context.
// https://java.net/jira/browse/JERSEY-2038
servletContext.setInitParameter("contextConfigLocation", "");
Here's the issue:
When the test is starting up, SpringComponentProvider, tries to initialize Spring with a dangerous assumption that I can't figure out how to correct - xml based configuration. Looking at the code, the trouble is this block
ServletContext sc = locator.getService(ServletContext.class);
if(sc != null) {
// servlet container
ctx = WebApplicationContextUtils.getWebApplicationContext(sc);
} else {
// non-servlet container
ctx = createSpringContext();
}
Running a JUnit test, ServletContext is null, and createSpringContext is called.
Here's the question:
Is there a way to run a test and specify a ServletContext/ServletContainer?
I believe this issue is covered by https://java.net/jira/browse/JERSEY-2259.
In short: they removed this functionality from Jersey 2.x and are treating it as a Feature Request (instead of regression) so it's not considered a high-priority item.

tomcat7, spring 3.0.5, errors, contexts

org.springframework.web.context.ContextLoader, in the event of an exception, does:
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
which looks quite useful, except the servlet context object it is making this call on is not connected, in any way that I can find, to the return value from Tomcat.addWebapp. So when I go looking for this attribute to see whether the startup worked right, I'm thwarted.
Is there a way to connect these two contexts?
Tomcat's documentation says you can get ServletContext from web-app's Context:
ServletContext getServletContext()
See JavaDoc on Context.

How to delay spring beans startup?

Having spring application (actually grails app) that runs apache-activemq server as spring bean and couple of apache-camel routes. Application use hibernate to work with database. The problem is simple. Activemq+Camel starts up BEFORE grails injects special methods into hibernate domain objects (actually save/update methods etc). So, if activemq already has some data on startup - camel starts processing messages w/o having grails DAO methods injected. This fails with grails.lang.MissingMethodException. Must delay activemq/camel startup before Grails injects special methods into domain objects.
If all these are defined as spring bean, you can use
<bean id="activeMqBean" depends-on="anotherBean" />
This will make sure anotherBean is initialized before activeMqBean
can you move MQ managment into a plugin? It would increase modularity and if you declare in plugin-descriptor
def loadAfter = ['hibernate']
you should have the desired behavior. Works for JBPM plugin
I am not sure in your case but lazy loading may also help e.g.
<bean id="lazybean" class="com.xxx.YourBean" lazy-init="true">
A lazily-initialized bean indicates to the IoC container to create bean instance when it is first requested. This can help you delay the loading of beans you want.
I know this question is pretty old, but I am now facing the same problem in the year 2015 - and this thread does not offer a solution for me.
I came up with a custom processor bean having a CountDownLatch, which I count down after bootstrapping the application. So the messages will be idled until the app has started fully and its working for me.
/**
* bootstrap latch processor
*/
#Log4j
class BootstrapLatchProcessor implements Processor {
private final CountDownLatch latch = new CountDownLatch(1)
#Override
void process(Exchange exchange) throws Exception {
if(latch.count > 0){
log.info "waiting for bootstrapped # ${exchange.fromEndpoint}"
latch.await()
}
exchange.out = exchange.in
}
/**
* mark the application as bootstrapped
*/
public void setBootstrapped(){
latch.countDown()
}
}
Then use it as a bean in your application and call the method setBootstrapped in your Bootstrap.groovy
Then in your RouteBuilder you put the processor between your endpoint and destination for all routes you expect messages coming in before the app has started:
from("activemq:a.in ").processRef('bootstrapProcessor').to("bean:handlerService?method=handle")

Resources