The basic problem I have here is that I have one xml file that is being used as a utility file and imported into other xml files. It defines a series of objects for connecting to a platform and providing an interface to it. The beans in this file are defined to be lazy-initialised so that if you do not want to connect to the platform you will not but if you start referencing the appropriate bean then everything should get up and running.
The basic problem I have is that one of the beans in this set is not explicity referenced by any of the others but it is required to be constructed as it will call a method on one of the other beans in order to "activate" it. (It is acting as a gate keeper by switching on/off the connectivity based on what it detects as the state of the platform).
Here's a dummy of the sort of XML setup I have:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd"
default-lazy-init="true">
<!-- Provides the connection to the platform -->
<bean id="PlatformConnection">
<constructor-arg ref="PlatformConnectionProperties" />
</bean>
<!-- This bean would be overriden in file importing this XML -->
<bean id="PlatformConnectionProperties"/>
<!-- Controls the databus to be on/off by listening to status on the Platform
(disconnections/reconnections etc...) -->
<bean lazy-init="false" class="PlatformStatusNotifier">
<constructor-arg ref="PlatformConnection" />
<constructor-arg ref="PlatformConnectionDataBus" />
</bean>
<!-- A non platform specific databus for client code to drop objects into -
this is the thing that client XML would reference in order to send objects out -->
<bean id="PlatformConnectionDataBus" class="DataBus"/>
<!-- Connects the DataBus to the Platform using the specific adaptor to manage the java object conversion -->
<bean lazy-init="false" class="DataBusConnector">
<constructor-arg>
<bean class="PlatformSpecificDataBusObjectSender">
<constructor-arg ref="PlatformConnection" />
</bean>
</constructor-arg>
<constructor-arg ref="PlatformConnectionDataBus" />
</bean>
</beans>
Now basically I want to remove the lazy-inits here that are required to get this thing to work properly. The objects referenced by the client XML are the PlatformConnection and the PlatformConnectionDataBus. How can I explicity declare that I want those other beans constructed if they are referenced?
You can add an explicit dependency from one bean to another by using the depends-on attribute:
<bean id="a" class="A"/>
<bean id="b" class="B" depends-on="a"/>
If I'm understanding your questin correctly, then I suggest you make all of your bean definitions lazy-init="true", and use depends-on to tie them together, for example:
<bean id="PlatformStatusNotifier" lazy-init="false" class="PlatformStatusNotifier">
<constructor-arg ref="PlatformConnection" />
<constructor-arg ref="PlatformConnectionDataBus" />
</bean>
<bean id="PlatformConnectionDataBus" lazy-init="false" class="DataBus" depends-on="PlatformStatusNotifier"/>
So if your client config were to express a dependency on PlatformConnectionDataBus, then that would trigger the initialisation of PlatformConnectionDataBus, which in turn would trigger the initialisation of PlatformStatusNotifier.
Related
I have the project structure as following -
Facade -> Service-> DAO
In the DAO layer, when the beans are initialized then many dependencies are injected from a property file. Therefore, the properties file must be read first and then the remaining dao beans must be created. When the application is started then it gives an error that Spring cannot resolve a placeholder.
The DAO-application-context.xml is like-
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="prop">
<value>app.properties</value>
</property>
</bean>
<import resource = "a-dao.xml" />
<import resource = "b-dao.xml" />
<import resource = "c-dao.xml" />
Now in all the child application contexts i.e. a-dao, etc, we have-
<bean ....>
<property name = "xyz">
<value>${appValue}<value/>
</property>
<bean>
The error received is that appValue cannot be resolved. I think that it may be due to incorrect sequence of bean creation. However, the same config is working in another larger project.
I have checked Order of Spring Bean Initialization but implementing that solution would not be feasible. Is there any other way ?
Reg this Block of Configuration, property prop seems to be wrong
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="prop">
<value>app.properties</value>
</property>
</bean>
According to the Spring documentation
You could use the property location or locations to set the one or multiple values of the properties file.
So the code should be refactored to
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>app.properties</value>
</property>
</bean>
Application background
There are 2 services in application. Lets call them
1) service A
2) service B
Service A basically copies files that match a particular criteria from the source directory to the destination directory. Using spring integration here.
The destination directory for service A is the source directory of service B.
Service B is constantly polling the directory for files and processes them and then moves them to another subdirectory called "processed".
Problem:
The original problem was that while service A is copying files to the destination directory, service B picks up the half copied files and processes them.
Tried solution
Refer to the service B integration-context.xml below. I attached a composite filter to the inbound channel. I added a custom filter called LastCreatedFileListFilter to this composite filter. This filter is based on lines of LastModifiedFileListFilter provided by spring-integration-file and this basically discards any file whose age (by created time) is less than 30 seconds.
This filter works perfectly and does not pick a file until its 30 seconds old. But the problem now is that I am using prevent-duplicates="true". So what happens is the first time service B polls the folder and the age of the file is less than 30 seconds it filters out the file but after 30 seconds, the filter does not filter out the file which is correct behavior but by now the service has marked this as a duplicate and rejects it.
So, my problem here is that I do want to keep a prevent duplicate check and also not process a file until its fully copied.
I am not very familiar with spring-integration and the two approaches I am looking to realize is:
1) not mark files as duplicate in the above scenario until it is processed by the application? is this possible? is so, is this advised?
2) In service A if I could first create files with a temporary name and then rename them after the copy is complete? the thing here is that service B will not pick up the files until they start with a configured name. This way, I do not have to trust the age property which could not be 100% decisive as the source and destination are on a different network and copy times could be large (#MurphysLaw).
But the problem here is that, I am having trouble conceptualizing how to best achieve this solution with spring integration. Any guidance or suggestions?
Please refer to integration context for service A for current implementation. Let me know if any thing needs clarification.
Service A
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-file="http://www.springframework.org/schema/integration/file"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/file
http://www.springframework.org/schema/integration/file/spring-integration-file.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder location="classpath:application.properties"/>
<bean name="redisMetaDataStore" class="org.springframework.integration.redis.metadata.RedisMetadataStore">
<constructor-arg ref="redisConnectionFactory" />
</bean>
<bean id="redisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="port" value="6379" />
</bean>
<int-file:inbound-channel-adapter id = "filesIn"
channel="fileChannel"
directory="file:${input.directory}"
filter="incomingCompositeFilter">
<int:poller id="fileInboudPoller" fixed-rate="${in.interval}" time-unit="SECONDS" />
</int-file:inbound-channel-adapter>
<bean id="incomingCompositeFilter" class="org.springframework.integration.file.filters.CompositeFileListFilter">
<constructor-arg>
<list>
<bean id="acceptOnceFilter" class="org.springframework.integration.file.filters.FileSystemPersistentAcceptOnceFileListFilter">
<constructor-arg ref="redisMetaDataStore"/>
<constructor-arg value="*"/>
</bean>
<bean id="notOlderThanDateFilter" class="com.fexco.bgeadmin.file.filter.NotOlderThanDateFilter">
<constructor-arg value="${file.lastModified.ignoreBeforeDate}"/>
</bean>
<bean id="documentConfigFilter" class="com.fexco.bgeadmin.file.filter.DocumentConfigFilter">
</bean>
</list>
</constructor-arg></bean>
<int:channel id="fileChannel"/>
<int-file:outbound-channel-adapter id="save-as-file"
auto-create-directory="true"
channel="fileChannel"
directory="file:${output.directory}"/>
</beans>
Service B
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-file="http://www.springframework.org/schema/integration/file"
xmlns:batch-int="http://www.springframework.org/schema/batch-integration"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/file
http://www.springframework.org/schema/integration/file/spring-integration-file.xsd
http://www.springframework.org/schema/batch-integration
http://www.springframework.org/schema/batch-integration/spring-batch-integration.xsd">
<int:channel id="inboundFileChannel"/>
<int:channel id="outboundJobRequestChannel"/>
<int:channel id="jobLaunchReplyChannel"/>
<int-file:inbound-channel-adapter id="filePoller"
channel="inboundFileChannel"
directory="${app.file.source}"
auto-create-directory="true"
prevent-duplicates="true"
filter="incomingCompositeFilter">
<int:poller fixed-rate="5000"/>
</int-file:inbound-channel-adapter>
<bean id="incomingCompositeFilter" class="org.springframework.integration.file.filters.CompositeFileListFilter">
<constructor-arg>
<list>
<bean id="fileNameFilter" class="org.springframework.integration.file.filters.RegexPatternFileListFilter">
<constructor-arg value=".*\.(xls|xlsx|csv)$" />
</bean>
<bean id="ageFilter" class="com.fexco.bgeadmin.integration.filter.LastCreatedFileListFilter">
<property name="age" value="30"/>
</bean>
</list>
</constructor-arg></bean>
<int:transformer input-channel="inboundFileChannel"
output-channel="outboundJobRequestChannel" method="toRequest">
<bean class="com.fexco.bgeadmin.integration.FileMessageToJobRequest"/>
</int:transformer>
<batch-int:job-launching-gateway request-channel="outboundJobRequestChannel"
reply-channel="jobLaunchReplyChannel"/>
<int:logging-channel-adapter channel="jobLaunchReplyChannel"/>
</beans>
The best solution for such problems is #2 - for A not to write the file to B "in-place". Using the last modified time is unreliable.
This is the standard procedure for the <int:file-outbound-channel-adapter/> - which uses a FileWritingMessageHandler underneath. It has a property temporaryFileSuffix, which is .writing by default. The file is renamed after being copied.
I am pretty new in Spring and I have a little doubt related the concept of namespace into my XML configuration files.
So for example into the root-context.xml file of a project on which I am working on there is this definition:
<jee:jndi-lookup jndi-name="java:jboss/datasources/myDbDS" id="datasource" expected-type="javax.sql.DataSource" />
that have the jee namepace that is also specified into the beans external container by:
xmlns:jee="http://www.springframework.org/schema/jee"
Now my doubt is, what exactly is this definition having id="datasource"? This one:
<jee:jndi-lookup jndi-name="java:jboss/datasources/myDbDS" id="datasource" expected-type="javax.sql.DataSource" />
Is it a classic bean of Spring having a specific namespace because it belong to a specific domain of bean (having a specific pourpose) or what?
As Explained in the spring doc:
The jee tags deal with Java EE (Java Enterprise Edition)-related
configuration issues, such as looking up a JNDI object and defining
EJB references
Here after an example from spring doc:
Without using jee jndi-lookup
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jdbc/MyDataSource"/>
</bean>
<bean id="userDao" class="com.foo.JdbcUserDao">
<!-- Spring will do the cast automatically (as usual) -->
<property name="dataSource" ref="dataSource"/>
</bean>
Using jee jndi-lookup
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/MyDataSource"/>
<bean id="userDao" class="com.foo.JdbcUserDao">
<!-- Spring will do the cast automatically (as usual) -->
<property name="dataSource" ref="dataSource"/>
</bean>
More details here
I am creating sample spring program to understand, local attribute of ref tag.
I have created two bean files
first one [applicationcontext.xml]
<bean class="org.vik.spring.SequenceGenerator" name="sequenceProperty_Other">
<property name="prefix">
<ref local="prefixGeneratorOther" />
</property>
<property name="suffix" value="23"></property>
</bean>
Second xml file [prefix_context.xml]
<bean class="org.vik.spring.DatePrefixGenerator" id="prefixGeneratorOther" p:prefix="other"/>
I have created app context like below
ApplicationContext applicationContext = new FileSystemXmlApplicationContext("applicationcontext.xml" ,"prefix_context.xml");
When I request for bean "sequenceProperty_Other", spring successfully returns it
SequenceGenerator sequenceConstrutornerator = applicationContext.getBean( "sequenceProperty_Other",SequenceGenerator.class);
What I could understand from this, is that as "prefixGeneratorOther" bean in not in same xml file (applicationcontext.xml) and I am using local attribute to refer it, Spring should through exception. But in my case its working. Am I missing some thing.
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- <bean class="org.vik.spring.SequenceGenerator" name="sequence"> </bean> -->
<bean class="org.vik.spring.DatePrefixGenerator" id="prefixGenerator"
p:prefix="122333">
</bean>
<bean class="org.vik.spring.SequenceGenerator" name="sequenceProperty_Locale">
<property name="prefix">
<ref local="prefixGenerator" />
</property>
<property name="suffix" value="23"></property>
</bean>
<bean class="org.vik.spring.SequenceGenerator" name="sequenceProperty_Other">
<property name="prefix">
<ref local="prefixGeneratorOther" />
</property>
<property name="suffix" value="23"></property>
</bean>
prefix_context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="org.vik.spring.DatePrefixGenerator" id="prefixGeneratorOther" p:prefix="other"/>
</beans>
Java class
ApplicationContext applicationContext = new FileSystemXmlApplicationContext("applicationcontext.xml",
"prefix_context.xml");
System.out.println(applicationContext.getBean("prefixGenerator", PrefixGenerator.class).getPrefix());
SequenceGenerator sequenceProperty = applicationContext.getBean("sequenceProperty_Locale",
SequenceGenerator.class);
System.out.println(sequenceProperty);
SequenceGenerator sequenceConstrutornerator = applicationContext.getBean("sequenceProperty_Other",
SequenceGenerator.class);
System.out.println(sequenceConstrutornerator);
This particular behavior works with any version after Spring 3.1.0 (included) in the 3.x branch. If you test this with the latest 3.0.x (which is 3.0.7) you'll get an exception. If you test with Spring 4, you'll get an exception, but a different one.
If you take a look carefully at the exception in Spring 3.0.7, this refers to XML parsing:
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:243)
at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:347)
at org.springframework.beans.factory.xml.DefaultDocumentLoader.loadDocument(DefaultDocumentLoader.java:75)
which means the restriction is at xml schema level (and I believe it's at Java code level, as well).
This behavior has changed in Spring 3.1.0 (and after) because of this JIRA issue. From all those JIRA issue it is linked to, this one seems to explain what happened: the restriction has been eliminated from 3.1 schema and the ref local entered in a kind of "deprecated" state (because in 3.1.x and 3.2.x one can use it) and in Spring 4 ref local has been entirely eliminated. In Spring 4 the documentation says ref local is not supported anymore and, also, the xsd schema has been updated (in the sense that ref doesn't accept local anymore).
On my web.xml I have a "springmvc" servlet declaration (which has a corresponding springmvc-servlet.xml)
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/myapp/*</url-pattern>
</servlet-mapping>
I also have my usual applicationContext.xml file.
Which one gets loaded first? The springmvc-servlet.xml or the applicationContext.xml?
The reason I'm asking this is whenever I place the <mvc:annotation-driven/> element in the applicationContext.xml, I get a Severe Context error. But when I put that element in the springmvc-servlet.xml, my web app runs fine.
Any ideas why?
On another web-app, I have the <mvc:annotation-driven/> inside the applicationContext.xml and it runs fine.
Addendum:
I do notice that the presence of aop:config poses conflict against mvc:annotation-driven
the applicationContext.xml context is parent to the dispatcher-servlet.xml context. I don't know whether this means it is loaded first, but it does not matter in your case:
<mvc:annotation-driven /> must be in the dispatcher-servlet.xml, because it belongs to the web-part of the application.
I solved my problem!
It turns out it has nothing to do with the load order or where the <mvc:annotation-driven/> is declared.
I tried deploying my web-app on another Tomcat and to my surprise there's a stack trace in the localhost log. I had a hint by trial and error that the conflict is with <aop:config/>. But what particular conflict?
Then I saw this error in the log file:
java.lang.ClassCastException: org.aspectj.weaver.ResolvedType$Array cannot be cast to org.aspectj.weaver.ReferenceType
So we have a cast exception. I googled that exact error above and found this: Spring 3: adding causes ClassCastException
It appears the thread starter and I have the same exact issue. So I downloaded the aspectj-1.6.10.jar but I was still missing a class. Then it turns out it should be the aspectjweaver-1.6.9
I was still using a very old aspectjweaver. It didn't have any version on its name. Problem solved. Case closed.
By the way as a bonus, I've manually unrolled the <mvc:annotation-driven/> element to its equivalent xml declaration:
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="order" value="0" />
</bean>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="webBindingInitializer">
<bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
<property name="validator" ref="validator" />
</bean>
</property>
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter" />
<bean class="org.springframework.http.converter.StringHttpMessageConverter" />
<bean class="org.springframework.http.converter.FormHttpMessageConverter" />
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter" />
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" />
</list>
</property>
</bean>
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
<bean id="conversion-service" class="org.springframework.format.support.FormattingConversionServiceFactoryBean" />
They're exactly the same when you declare the <mvc:annotation-driven/> based on what I've researched.
Thanks to everybody who helped me out.
Except for web.xml there is no predefined order.
This happens:
web.xml is loaded by the servlet engine, this triggers the load of all defined servlets, filters, listeners,
the ContextLoaderListener loads the
root application context XML, this
might include a bean definition for a
LocalSessionFactoryBean, triggering
the load of all Hibernate mapping XML
files
the DispatcherServlet loads the web
application context XML
Study the web.xml to determine the order in each case.
see also:
link
You probably have to add the mvc namespace to the application context:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"
>
(other namespaces stripped)