I've read Spring In Action, and prefer Java config over XML config. So I used Java config to write my app, but our deployment environment requires me to use XML config. So I wrote an XML config, and it's only function is to import the root Java config.
The Java config code looks like this:
package com.somegroup.app;
#Configuration
#ComponentScan(basePackages = "com.tianchengsys.crawlers.cqs")
public class AppCtxConfig {
#Bean
public SomeType aSomeType() {
return new SomeType()
}
}
and the XML config looks like this:
<?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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<context:annotation-config />
<bean class="com.somegroup.app.AppCtxConfig" lazy-init="false" />
</beans>
When I created a ClasspathXmlContext("classpath:spring-context.xml") in Eclipse, the SomeType bean defined in Java config is initialized, and registered to springs ApplicationContext. But when I deployed this app (all dependencies are in a lib directory), the AppCtxConfig bean defined in the XML config was just treated an ordinary bean (not configuration).
It was created, but the beans defined in it were not initialized. Spring some times warned the someType method in the Java config should be static. I did changed it to static, it also didn't work.
This is because you are creating AppCtxConfig as a regular bean, which it isn't.
As the commentor suggested, add the component-scan on and set base-package to the package where your config class is located in:
<!-- Scan the JavaConfig -->
<context:component-scan base-package="com.somegroup.app" />
If your app package is the root package, with all subpackages inside, add a new config package and move the AppCtxConfig inside it.
So add:
<!-- Scan the config package with AppCtxConfig inside it -->
<context:component-scan base-package="com.somegroup.app.config" />
Related
I have a tomcat application with jndi.xml file that has placeholder. This file contains placeholder ${...} and I want it to be replaced from environment variable.
jndi.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:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd">
<bean id="widgetsRestBaseUrl" class="java.lang.String" factory-method="valueOf">
<constructor-arg value="${widgetsRestBaseUrl}"/>
</bean>
</beans>
pom.xml:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.13.RELEASE</version>
</dependency>
From my understanding, PropertySourcesPlaceholderConfigurer resolves ${...} in bean definition , so I expected it to work, but it doesn't. Am I missing anything from here? I do see PropertySourcesPlaceholderConfigurer class in my project from spring. And I also do set environment variable, checked using printenv.
EDIT: I found that I need to have some <context:property-placeholder />, but not sure what it means.
Exposing jndi variables as property place holder
After some research, I found that adding <context:property-placeholder ignore-unresolvable="true"/> in my context.xml file did the trick. From Exposing jndi variables as property place holder
I have a problem with Environment env.getproperty, env not find local properties, but it find system properties. I dont know about this so much and I need to solve it. Please, help me.
Attached my code and its configuration.
Controllers.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:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!-- Scans within the base package of the application for #Components to
configure as beans -->
<mvc:annotation-driven />
<context:component-scan base-package="com.mret.client.controller" />
<context:component-scan base-package="com.mret.client.security" />
<context:property-placeholder location="classpath*:paremeters.properties" />
Paremeters.properties:
url.services.search=http://localhost:8080/mretcore/search
url.services.orderdetail=http://localhost:8080/mretcore/orderdetail?orderid=
Controller:
#Controller
public class OrdersController {
RestClient restClient = new RestClientImpl();
#Autowired
private Environment env;
String url = env.getProperty("url.services.search");
etc....}
enter image description here
property-placeholder does not place properties into env. It is for variables set on OS level.
better use System.getProperty("property_name") which includes env, JVM properties, -D properties passed into java command line and yes - those from property-placeholder.
Also you may consider to use your url as bean property and do not get it explicitly, but by spring bean property definition like ${url.services.search}
instead of having property name in code. After time it may hard to find where what property loaded. It is better approach...
I'm trying to inject a bean that was defined on a XML into an annotated, It is only annotated and not declared on XML, I think that is just something that I'm missing here is my *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:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
...
<bean id="userBusiness" class="org.springframework.ejb.access.LocalStatelessSessionProxyFactoryBean">
<property name="jndiName" value="java:global/app-common/app-common-core/UserBusinessImpl" />
<property name="businessInterface" value="com.app.common.business.UserBusiness" />
</bean>
...
<context:annotation-config/>
<context:component-scan base-package="com.app.common.jsf" />
</beans>
Here's the component:
#Component
public class AppAuthorization {
#Autowired
private UserBusiness userBusiness;
#Autowired
private AppLogin sabiusLogin;
...
#Local
public interface UserBusiness {
User listUserByFilter(User user) throws UserBusinessException;
...
#Stateless
#Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT)
#Interceptors({SpringBeanAutowiringInterceptor.class})
public class UserBusinessImpl implements UserBusiness {
#Autowired
private ProgramasUsuariosDao programasUsuariosDao;
...
When I try to access the AppAuthorization Spring says that:
Could not autowire field: private com.app.common.business.UserBusiness com.app.common.jsf.AppAuthorization.userBusiness"
Seems that the annotated bean can't see the declared one, but search and seems that I only needed to add the annotation-config to the XML, is this right? Hope some can help me.
EDIT
I think that this is the most important part of the stack trace:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.app.common.business.UserBusiness] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:997)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:867)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:779)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:503)
... 201 more
Following the steps on the context creation I see no bean registered tha can be seen by annotations just when springs creates the context based on the xml is that I can see all the beans that wre created.
EDIT 2
This is the beanRefContext.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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean id="contexts" class="com.app.common.spring.ClassPathXmlApplicationContext" />
</beans>
This is the class that loads the XML context files:
public class ClassPathXmlApplicationContext extends org.springframework.context.support.ClassPathXmlApplicationContext {
public ClassPathXmlApplicationContext() {
super((System.getProperty("module.context.file").split(";")));
}
}
As I said, the annotated beans cannot see the XML ones so, spring cannot autowire them.
EDIT 3
I don't have a #Configuration bean (I'm not using AnnotationConfigApplicationContext), all the config is in the XML and if I try to create one the server doesn't start, it's a legacy system with spring 3.2 and EJB 3.0 and I can't change this aspect now.
Thanks in advance!
I think you missed to specify #Component annotation for the UserBusiness class
EDIT:
Can you make the component-scan config to com.app.common instead of com.app.common.jsf
What seems to work was create a #Configuration import the xml that have the bean declaration (with #ImportResource) and don't scan it's package in XML.
For some reason if I declare the file in the XML the server don't start, it's strange because I have no definition anywhere that I'm using an annotation configuration.
I'm trying to have my project's Strings/ messages stored in an external .properties file. I think I have everything wired up OK, but still I get:
org.springframework.context.NoSuchMessageException: No message found under code 'subtype.user.client' for locale 'null'.
Whenever I try:
String string = messageSource.getMessage("subtype.user.client", null, null);
My spring xml config files are as follows. Since the project is really big with lots of beans, I have different spring xml config files defining different types of beans, and a main spring.config.xml file that wires them all together.
Messages file named messages.subtypes
subtype.user.user=User
subtype.user.client=Client props
subtype.user.staff=Staff
subtype.user.clerk=Clerk
subtype.user.secretary=Secretary
Messages beans file called spring.messages.config.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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename">
<list>
<value>messages.subtypes</value>
</list>
</property>
</bean>
<bean id="myProjectLangs" class="myprojectbase.MyProjectLangs">
<property name="messageSource" ref="messageSource"></property>
</bean>
</beans>
The main spring.config.xml config file that wires all the beans together via <import resource="classpath:filename.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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">
<aop:aspectj-autoproxy />
<import resource="classpath:spring.messages.config.xml"/>
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource" />
<context:annotation-config />
<context:component-scan base-package="myprojectbase"/>
</beans>
You get this error because you pass the Locale parameter as null. Try
String string = messageSource.getMessage("subtype.user.client", null, Locale.ENGLISH);
Even though you have not defined a file messages.subtypes_en.properties defined it should fall back to messages.subtypes.properties
A couple of things come to mind looking at your code any of which might cause the problem:
Your xml config name contains "." as separators. This is against conventions. Consider renaming your config file to spring-messages-config.xml
Your language properties file has no properties suffix, again convention suggests to name this file messages-subtypes.properties
In both your application context xml files you define a bean named messageSource. Consider deleting one of them.
My prime suspicion as to why your code does not work lies with the way you define basename on ReloadableResourceBundleMessageSource. Looking at the JavaDoc for setBasename method there is some form of convention of configuration at work:
Set a single basename, following the basic ResourceBundle convention of not specifying file extension or language codes, but in contrast to {#link ResourceBundleMessageSource} referring to a Spring resource location: e.g. "WEB-INF/messages" for "WEB-INF/messages.properties", "WEB-INF/messages_en.properties", etc. XML properties files are also supported: .g. "WEB-INF/messages" will find and load "WEB-INF/messages.xml", "WEB-INF/messages_en.xml", etc as well.
This suggests that once you have renamed your message properties file to messages-subtypes.properties, you should change your config to <value>classpath:messages-subtypes</value>, make sure that the file is in the classpath and everything should start working.
Try renaming the messages.subtypes file to messages.subtypes.properties.
Is there a special way for doing this?
What i got is:
config.properties with param.key=value
web.xml with ContextLoaderListener that reads the configuration
pages-servlet.xml that defines servlet beans.
What I want is to configure one of the beans in pages-servlet.xml with param.key.
I'm using <property name="myField" value="${param.key}"/> in the xml but I see that the field is configured with ${param.key} instead of 'value'.
What is the right way to configure the bean?
Ok, I solved it by importing application context file that defines configuration bean into pages-servlet.xml.
It works, but seems very wrong.
Property placeholder is what you want.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:property-placeholder location="classpath:/config.properties" />
<bean id="mybean" class="...">
<property name="xxx" value="${prop.value}" />
</bean>
</beans>