I'm using Spring to auto-wire beans for configuration. Some parameters come from a properties file:
<bean id="mydb" class="myproject.mydb" autowire="constructor">
<constructor-arg name="host" value="${mydb.host}" />
<constructor-arg name="db" value="${mydb.db}" />
<constructor-arg name="user" value="${mydb.user}" />
<constructor-arg name="password" value="${mydb.password}" />
</bean>
Is there a way to auto-wire these properties based on the bean id so that I would just have to write the following?
<bean id="mydb" class="myproject.mydb" autowire="constructor" />
Edit: The point of this is to not have to explicity specify the non-bean constructor arguments. I want Spring to automatically check the properties for beanId.constructorArgName
To achieve exactly what you want, I think you'd need to implement a BeanPostProcessor and provide your custom wiring logic (where you read the .properties file) in postProcessBeforeInitialization. The bean name is available to that method, but there are multiple problems with this. The first is that argument names are not necessarily available at runtime, so indexes might be a better option. The second is that you already have an instantiated bean (so a default constructor would need to exists), and you'd instantiate another, throwing the first one away which is wasteful. To use the instance that already exists, you'd need to wire it by properties, not constructor, which violates encapsulation and is not what you asked. The third is that it's not at all obvious what is going on. So, all in all, you are probably better off avoiding this completely.
In your class myproject.mydb
#Autowired
public mydb(#Value("mydb.host") String host, ...){...}
As per your question, the only way Property values can be injected to the constructor is through the XMLfile as done above or using the #Value("${some.property}") annotation.
Refer this for more info
Use #Value("property key") annotation. look at eg.: http://java.dzone.com/articles/autowiring-property-values
Related
In my Java/spring project there are lots of beans configured in an xml like,
<beans>..
<bean id="beanOne" class=...>
<property name="x" value="1"/>
<property name="y" value="something"/>
<property name="z" value="something else"/>
</bean>
</beans>
"beanOne"'s properties(x,y,z) values keep changing for different needs/machines. I can create different xml files having different values, one for each need/machine. But I want to write some custom bean creation logic so that I can define different properties in a single properties (or) json file and the custom class takes care of creating the beans with appropriate values from that single properties (or) json file for all needs/machines.
So how to can I do that in spring? - Extend AbstractFactoryBean, implement FactoryBean, implement BeanFactory, or something else? I just need the logic/skeleton of how to do that using spring.
Follow these steps to do the same,
create the object for your required bean.
Set the required properties for that object, you can fetch it from anywhere you want.
Register that object in beanFactory as a bean.
Reference : https://wordpress.com/post/anilagrawal038.wordpress.com/3
Can Spring bean be a reference to another bean? It doesn't seem to work:
<bean id="player1" class="some.package.Player" />
<bean id="player2" ref="player1" />
If this is possible, is it useful? So far, I was thinking that every bean must represent a unique object, but some idea came to my head: what if I had a Singleton class called e.g. Sun with a "public static Sun getInstance()" method and I would make two beans being the same object?
<bean id="sun1" class="some.package.Sun" factory-method="getInstance" />
<bean id="sun2" class="some.package.Sun" factory-method="getInstance" />
Looking at the below
<bean id="player1" class="some.package.Player" />
<bean id="player2" ref="player1" />
I think you want to refer same bean with two or more names. If so, you can have comma separated list or ids as (alias concept)
<bean id="player1, player2" class="some.package.Player" />
Now you can refer the bean with either player1 or player2.
Similarly,
<bean id="sun1" class="some.package.Sun" factory-method="getInstance" />
<bean id="sun2" class="some.package.Sun" factory-method="getInstance" />
can be replaced with
<bean id="sun1, sun2" class="some.package.Sun" factory-method="getInstance" />
and this allows you to refer the same bean with two different ids.
And to understand when aliasing is useful, quoting from https://vladmihalcea.com/why-i-like-spring-bean-aliasing/,
Bean aliasing allows us to override already configured beans and to
substitute them with a different object definition. This is most
useful when the bean definitions are inherited from an external
resource, which is out of our control.
Beans are generally singletonic, so they represent one object per context. Standard singleton design pattern in java creates one object per class loader. I think in your case you will re-create one object twice, once with Spring beans, and once with own class loader executed implementation. So both suns will be the same when you compare their hash codes via .getInstance().hashCode().
I have a situation very similar to "Inject a file resource into Spring bean"
I have a controller that uses some .jasper compiled files and I am declaring them as such
//...
#Controller
public class InvoicingController {
private Resource quoteTemplate;
...//
And in my context configuration file
<bean id="invoicingController" class="x.x.InvoicingController">
<property name="quoteTemplate" value="/WEB-INF/jasper/Quote.jasper" />
...
I set a breakpoint on the setQuoteTemplate() function and it is being called and the Resource object is being set properly when I initialize the container. However when I actually hit the controller quoteTemplate is null.
I am under the understanding that Controllers are singletons and unless there is a gap in my understanding I am not sure why the values that are set during the container's initialization become null when I hit a url that the controller handles.
EDIT:
Thanks #Sotirios Delimanolis
I ended up declaring beans as such:
<bean id="quoteFile" class="java.io.File">
<constructor-arg value="resources/jasper/Quote.jasper" />
</bean>
<bean id="quoteTemplate" class="org.springframework.core.io.FileSystemResource">
<constructor-arg ref="quoteFile" />
</bean>
And then #Autowireing the dependencies as such
#Autowired #Qualifier("quoteTemplate") private Resource quoteTemplate;
#Qualifier is used because I have multiple Resource implementation classes declared as beans and this makes sure the correct one gets used.
You can't be using both the #Controller annotation and a <bean> declaration, unless you don't have a component-scan. You will end up with two bean definitions where the last one will overwrite the first one.
In this case, it seems like the component-scanned bean definition comes second and overwrites the bean you created with <bean>.
Choose which bean declaration method you want to use.
I want to inject a map containing all the properties that spring knows of (which are inserted by a library) to a config class that I have through the spring xml. Is that possible?
<bean class="Config">
<constructor-arg name="env">
<map>
//inject all properties?
</map>
</constructor-arg>
</bean>
Why don't you just inject the Spring Context? Through the Context, you can look up any bean via its name.
Edit:
From this answer, you could also use the following:
<bean class="Config">
<constructor-arg name="env">
<util:properties location="${path.to.properties.file}"/>
</constructor-arg>
</bean>
Where your "env" constructor argument is a java.util.Properties object.
For later versions of Spring (including spring-boot) that support the injection of an Environment you can use this to access all properties loaded.
To answer this question inject a AbstractEnvironment so that you are able to call the getPropertySources() method that will allow you to see where the properties have been loaded from (e.g. a file, OS variables, etc)
#Autowired
public Config(AbstractEnvironment environment)
{
MutablePropertySources propertySources = environment.getPropertySources();
// inspect propertySources to see all properties loaded by Spring
}
Can you not extend the library class that you use and instantiate your bean instead of the default library one? Then you would be able to inspect all the values.
Otherwise, if you know the signature of the library, you can always use AOP to weave some code around the library and get access to the properties there. A bit more complicated, but still gets you where you need to go. You can definitely use AspectJ (which requires a little more config) or even Spring AOP, depending how things are being accessed.
If you want/need more insight on this, let me know.
I have a static method I have no control over: MyUtils.getServiceURL() which returns a URL. I need to extract just the port from this URL to set a property on a bean:
<bean id="myBean>
<property name="defaultPort" value="?????"/>
</bean>
I can get the string value of the URL as a bean like this:
<bean id="serviceURL" class="MyUtils" factory-method="getServiceURL" />
I'm probably just going to write a method to parse the URL in myBean and extract the port. I was wondering if there was a way to avoid having to do this, and configure this directly in the spring context?
No need for custom classes, or parsers. Remember, a bean is just a class with get/is/set methods. A java.net.URL class qualifies as such.
Solution: Use a java.net.URL as a Spring-configurable bean and call it's getPort method.
Remember, in Spring, you can wire anything as a bean very easily so long as it sports methods using the get/is/set Bean convention. The java.net.URL class does such a thing.
** warning ** I'm just typing this out of my a$$, you'll have to check for any syntax shenanigans that I might be introducing in this Spring-config pseudo-code. One thing that is certain is that the concept will work with Spring 2.5 and that it relies on the util schema.
If you are using an older version of Spring, you'll have to use a PropertyPathFactoryBean. If you are using Spring 3.0, you'll want to use Spring expression language (EL), but I can't comment on the later since I'm not familiar with Spring 3.0.
In java:
int port = (new URL(MyUtils.getServiceURL()).getPort()
In Spring:
<bean id="serviceURL" class="MyUtils" factory-method="getServiceURL" />
<bean id="myURL" class="java.net.URL">
<constructor-arg>
<ref-bean="serviceURL"/>
</constructor-arg>
</bean>
<util:property-path id="defaultPort" path="myURL.port"/>
<bean id="myBean>
<property name="defaultPort" ref="defaultPort"/>
</bean>
There might be a way to consolidate all these four expressions into three or less, don't know if that will improve readability, though. The concept remains the same, though. Treat a java.net.URL instance as a bean, set its URL via its constructor, and get a hold (via Spring) of its getPort() method.
** edit **:
If you are using Spring 2.5 you can create an inline groovy bean that does all that for you. I've seen people doing that as integration glue to get rid of multitude of temp Spring bean place holders. That's the best choice IMO when you need to define a class (when it's simpler than just using Spring tags) and when you know such a class won't be used outside of Spring wiring of things.
Not I can think of. Either way, you probably have to write something to parse the port out. Since you have no control of that static method, perhaps you may want to utilize the adapter pattern to hide that static method. Doing so also makes your code easier to test because you can easily mock that external API out. For example:-
public interface URLServiceAdapter {
int getServiceURLPort();
}
public class URLServiceAdapterImpl implements URLServiceAdapter {
public int getServiceURLPort() {
return MyUtils.getServiceURL().getPort();
}
}
Your beans will then rely on your adapter class instead of MyUtils.getServiceURL() directly:-
<bean id="urlServiceAdapter" class="project.URLServiceAdapterImpl" />
That way, you can do something like this:-
#Autowired
private UrlServiceAdapter urlServiceAdapter;
...
bean.setDefaultPort(urlServiceAdapter.getServiceURLPort());
SpEL is your friend.
<bean id="myBean>
<property name="defaultPort"
value='#{ T(com.foo.MyUtils).getServiceURL().split(":")[2].split("/")[0] }'/>
</bean>
Enjoy,