converting java variable to spring beans - java

I am working on spring boot application. I want to define a variable in a class file as bean so that it is being initialised only once. Below is the source code.
Configuration cfg = new Configuration();
//Load template from source folder
Template template = cfg.getTemplate("src/helloworld.ftl");
// Build the data-model
Map<String, Object> data = new HashMap<String, Object>();
data.put("message", "Hello World!");
// Console output
Writer out = new OutputStreamWriter(System.out);
template.process(data, out);
out.flush();
I want to initialise the configuration object cfg & the template (starting 2 lines of the code) only once during application start and later use them wherever required in application classes.
How can I achieve this with bean?
Or is there any other better way to achieve this?

Create a new class and use the #Configuration annotation to load the beans when the application start up.
#Configuration
public class SpringConfiguration{
#Bean
public Configuration getConfigurationBean(){
return new Configuration();
}
}

One thing you can do is put the instantiation and initialization of the variables in their own method and annotate every method with the #Bean annotation.
If you do this, you should annotate the class with #Configuration.
The 2 methods of yours would look something like this:
#Configuration
public class ConfigurationBean {
#Bean
public Configuration configuration() {
return new Configuration();
}
#Bean
public Template template() {
return configuration().getTemplate("...");
}
}
Additionally, if you don't want to instantiate the Configuration as a separate bean, you can merge the 2 methods above.
======= UPDATE to answer question in the comment =======
If you want to use the newly defined Template bean for example in other classes, you need to annotate those classes with #Component, so that they become beans as well.
An example:
#Component
public class OtherClassBean {
private final Template template;
public OtherClassBean(Template template) {
this.template = template;
}
}
please be careful here, because from now on, you can't manually instantiate OtherClassBean, meaning that a line like new OtherClassBean(...) is wrong in 99% of the cases and might result in unexpected behavior.
This is because all beans are meant to be managed by Spring, which can only be achieved if Spring instantiates those classes.
The only exception from this rule of thumb is in my initial answer, where you instantiate a bean in a method that is annotated with #Bean.
I know this is a confusing topic for most people trying to learn this, so don't be shy to ask more questions.

Related

Create bean only if property file/xml file exists [duplicate]

Lets say i have two beans:
class MyBean implements BeanInterface(){}
class MyBean2 implements BeanInterface(){}
And if specific property exists, i want to create MyBean, otherwise I want to create MyBean2(). How can i do this?
#Bean
#ConditionalOnProperty(name = "property.validation")
public BeanInterface beanInterface() {
return new MyBean();
}
works if I want to create MyBean if property exists, but how do I create MyBean2 if it doesn't?
#Bean
#ConditionalOnMissingBean(MyBean.class)
public BeanInterface beanInterface() {
return new MyBean2();
}
complains that method with same name exists, and if i understand it correctly, the methods name need to be camelCase name of the bean.
How do i do this?
Thanks
//edit i tried:
#Bean
#ConditionalOnProperty(name = "property.validation")
#Order(1)
public BeanInterface beanInterface() {
return new MyBean();
}
#Bean("beanInterface")
#ConditionalOnMissingBean(MyBean.class)
#Order(2)
public BeanInterface beanInterface() {
return new MyBean2();
}
but it didnt work, second bean is not getting created when property is missing.
You can specify bean name #Bean("beanInterface") then method name can be anything.
You have Java configuration at your hands, so use that to your advantage. Not everything needs annotations to be fixed.
#Bean
public BeanInterface myBean(Environment env) {
String validation = env.getProperty("property.validation", String.class);
return validation != null ? new MyBean(validation) : new MyBean2();
}
The name of the method doesn't matter it can be anything you like.
Spring and Spring boot provide a a following solution: If you need to choose one implementation of the interface at runtime, than you inject all implementations and choose appropriate one at runtime. Assuming that you have an interface DataSource with multiple implementations here is how you inject them all:
#Autowired
private List<DataSource> dataSources;
You can read about this solution here.
This is a standard solution, but I really don't like it as it is waistful to inject all implementations. So, I wrote a feature that is available as part of MgntUtils open-source library. That feature allows you to create a static factory per each interface, and once you add any implementation of that interface declared as a Bean, that implementation will be added automatically at start up into a relevant factory. So, instead of injecting all implementations in your class you at runtime take from the factory needed implementation. I think it is much more elegant solution, and it has been battle-tested and it works well. Here is Javadoc that explains the concept and has a detailed example on how to use it: Lifecycle management. Also here is the article that describes this feature in detail: Non-intrusive access to "Orphaned" Beans in Spring framework. The library is available as Maven artifact at Maven central ad also on Github including javadoc and source code. In the source code there is a working example on how to use this feature

Spring profile annotation multiple beans

Let's say I have a library (I cannot change it). There is a class Consumer that uses a spring component of class A.
#Component
public class Consumer{
#Autowired
private A a;
}
In my configuration class I want to define two beans of same class A depending on the profile.
#Configuration
public class Config {
#Bean
#Profile("!dev")
A a1(){
return new A();
}
#Bean
#Profile("dev")
A a2(){
return new A();
}
}
But when I start the app, I get next exception
Parameter 1 of constructor in sample.Consumer required a single bean, but 2 were found:
I can't get how to fix that. I've tried to create 2 separate configs for that with profile annotation and single bean there, but it also did not work.
Marking one bean #Primary also does not help.
Do you guys know how to fix that? Thanks!
UPD.
Let me make it more specific. That class is a part of dynamodb spring starter. Consumer - DynamoDBMapperFactory. My bean - DynamoDBMapperConfig. So I want to have 2 versions of DynamoDBMapperConfig in my app.
You need to stop scanning package where Consumer declared.
#Profile behaves differently if it's applied to the #Bean annotated method.
From Profile doc.:
Use distinct Java method names pointing to the same bean name if you'd like to define alternative beans with different profile conditions
This means, you should do:
#Configuration
public class Config {
#Bean("a")
#Profile("!dev")
A a1(){
return new A();
}
#Bean("a")
#Profile("dev")
A a2(){
return new A();
}
}
Note the same bean names.

Where do I put my XML beans in a Spring Boot application?

I'm getting back into Spring (currently v4). It's all wonderful now with #SpringBootApplication and the other annotations but all the documentation seems to forget to mention how I define other beans in XML!
For example I'd like to create an "SFTP Session Factory" as defined at:
http://docs.spring.io/spring-integration/reference/html/sftp.html
There is a nice bit of XML to define the bean but where on earth do I put it and how do I link it in? Previously I did a:
ApplicationContext context = new ClassPathXmlApplicationContext(
"classpath:applicationContext.xml");
to specify the file name and location but now that I'm trying to use:
ApplicationContext ctx = SpringApplication.run(Application.class);
Where do I put the XML file? Is there a magic spring name to call it?
As long as you're starting with a base #Configuration class to begin with, which it maybe sounds like you are with #SpringBootApplication, you can use the #ImportResource annotation to include an XML configuration file as well.
#SpringBootApplication
#ImportResource("classpath:spring-sftp-config.xml")
public class SpringConfiguration {
//
}
You also can translate the XML config to a Java config. In your case it would look like:
#Bean
public DefaultSftpSessionFactory sftpSessionFactory() {
DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory();
factory.setHost("localhost");
factory.setPrivateKey(new ClassPathResource("classpath:META-INF/keys/sftpTest"));
factory.setPrivateKeyPassphrase("springIntegration");
factory.setPort(22);
factory.setUser("kermit");
return factory;
}
You can put this method in the class with the #SpringBootApplication annotation.
Spring boot ideal concept is avoid xml file. but if you want to keep xml bean, you can just add #ImportResource("classPath:beanFileName.xml").
I would recommend remove the spring-sftp-config.xml file. And, convert this file to spring annotation based bean. So, whatever class has been created as bean. Just write #Service or #Component annotation before class name. for example:
XML based:
<bean ID="id name" class="com.example.Employee">
Annotation:
#Service or #Component
class Employee{
}
And, add #ComponentScan("Give the package name"). This is the best approach.

Spring Property Injection with Play2 Framework

I like many features of Play Framework 2 (I'm using it with Java) but, as a fan of Dependency Injection, I love also Spring and particularly, its way to inject configuration into objects by just using the #Value annotation.
Therefore, I would love to know how to inject into an instance variable the value of a property using Play's built-in property resolution mechanism. Something like this:
#Component
public class SpringBeanWithinAPlay2Application {
#Value("${application.timeout:10}")
private int timeout;
}
Any clue anyone?
Many thanks in advance.
I had the same problem a while ago and this was my way of making this work:
Firstly, when you boostrap your Spring Application context (I use annotation based configuration but the same should work for XML based), you have to add a custom PropertySource, which is the way Spring enables the addition of new way of resolving properties. Something like this:
public static void initialize() {
ctx = new AnnotationConfigApplicationContext();
ctx.getEnvironment().getPropertySources().addFirst(new PlayFrameworkPropertySource());
ctx.scan("somepackage");
ctx.refresh();
}
The custom class PlayFrameworkPropertySource is the one that does the magic:
public class PlayFrameworkPropertySource extends PropertySource<Object> {
public PlayFrameworkPropertySource() {
super("Play Framework properties resolution mechanism");
}
#Override
public Object getProperty(String propertyName) {
// or ConfigFactory.load().getString(propertyName), as you prefer...
return Configuration.root().getString(propertyName);
}
}
In order for all this to work, you just need to do one more thing: explicitly declare a bean of type PropertySourcesPlaceholderConfigurer in some #Configuration class you might be using:
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
Important Note: this bean must be static, as it's a BeanFactoryPostProcessor and it should be loaded prior to any other regular #Bean.
This worked like a charm for me, hope this is helpful to someone else!
Cheers,
Jonathan

Spring - passing a custom instance to a constructor

I'm trying to implement a command-query design pattern into
a MVC spring based application.
I have, for example, some decorated commands using decorator pattern
like bellow:
ICommandHandler handler =
new DeadlockRetryCommandHandlerDecorator<MoveCustomerCommand>(
new TransactionCommandHandlerDecorator<MoveCustomerCommand>(
new MoveCustomerCommandHandler(
new EntityFrameworkUnitOfWork(connectionString),
// Inject other dependencies for the handler here
)
)
);
How can I inject such a handler into a controller constructor? Where should
I instantiate this handler? A place where this can be instantiated can be
the controller constructor, but this isn't the best solution. Any other ideeas?
Thanks
If you're using PropertyPlaceholderConfigurer (old) or PropertySourcesPlaceholderConfigurer (new), and your connection string is in a .properties file or environment variable you can do the following for the connection string. You can also autowire objects into a configuration class and annotate a method with #Bean to do what the Spring context xml does. With this approach you can create your beans as you wish and they're available to autowire just like you defined them in xml.
#Configuration
public class MyAppConfig {
#Autowired private MyType somethingToAutowire;
#Bean
public ICommandHandler iCommandHandler(#Value("${datasource.connectionString}")
final String connectionString) {
return new DeadlockRetryCommandHandlerDecorator<MoveCustomerCommand>();
// You obviously have access to anything autowired in your configuration
// class. Then you can #Autowire a ICommandHandler type into one of your
// beans and this method will be called to create the ICommandHandler (depending on bean scope)
}
}

Categories

Resources