Better Design to access XmlBeanFactory with Spring - java

I am trying to find a better what to do this. In Spring a lot of my classes need to load beans (objects) from XmlBeanFactory. So I put the following line into most of my classes
private static XmlBeanFactory beanFactory = new XmlBeanFactory(
new ClassPathResource("config.xml"));
Does anyone know of a better what for me to do this so I don't have to have this in most of my classes?

You can make your class implement BeanFactoryAware that will give you instance of the bean factory, so you could call one of BeanFactory.getBean(..) methods directly.
public class MyFactoryBean implements BeanFactoryAware {
private BeanFactory beanFactory;
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
public void someMethod() {
MyBean myBean = beanFactory.getBean("myBean", MyBean.class);
...
}
}

Related

Spring context initialization with runtime values

I'm trying to integrate Spring in a standalone Swing application.
The Swing application asks for login details at start-up, which should then be used to create a singleton DataSource Bean.
However I can't come up with a way to pass those login info (as Java object) to the Spring ApplicationContext during initialization (which would then be passed down to the #Bean producer method).
Any ideas?
Possible solution:
#SpringBootApplication
public class DemoSwingApplication {
public static void main(final String[] args) {
...
final var loginInfo = buildLoginInfo();
try (final var context = new AnnotationConfigApplicationContext()) {
context.getBeanFactory().registerSingleton("loginInfo", loginInfo);
context.register(DemoSwingApplication.class);
context.refresh();
}
}
}
There are multiple ways in which you can do this,
Using BeanDefinitionRegistryPostProcessor - Create a bean which will implement BeanDefinitionRegistryPostProcessor and then store the BeanDefinitionRegistry instance and dynamically register your bean.
#Component
public class DbConfigurer implements BeanDefinitionRegistryPostProcessor, BeanFactoryAware {
private BeanDefinitionRegistry beanDefinitionRegistry;
#Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
this.beanDefinitionRegistry = beanDefinitionRegistry;
}
public void registerDataSourceBean() {
beanDefinitionRegistry.registerBeanDefinition("dataSource", new RootBeanDefinition(DataSource.class,
BeanDefinition.SCOPE_SINGLETON, yourDataSourceBeanSupplier));
}
}
Using BeanFactoryAware - This is similar to implementation that you provided but by implementing BeanFactoryAware interface but downside of this is to check for BeanFactory instance -
#Component
public class DbConfigurer implements BeanDefinitionRegistryPostProcessor, BeanFactoryAware {
#Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) beanFactory; // Need to cast
}
}
And then in your UI component, inject this And and register bean when config properties are available -
#Component
public class MainWindow extends JFrame {
private final DbConfigurer dbConfigurer;
// register bean once user provides config properties
}
and start your application using headless mode disabled -
#SpringBootApplication
public class DesktopApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(DesktopApplication.class).headless(false).run(args);
}
}

Pretty way to inject Spring properties to object not managed by Spring

I have a Spring application and I'm using a third party library. There's no constructor, everything is configured and instantiated inside of this library.
I can add some custom behavior by creating a class. What I need is to add my Spring properties to this class.
Here's the class:
public static class CustomClass implements ExternalClass {
#Override
public Object create() {
//Here I would like to inject my properties.
}
}
I'm looking for a pretty approach.
Use the #Configurable annotation on this class to make it possible to inject Environment or directly a property via #Value as usual. This is the documentation of this annotation.
#Configurable
public static class CustomClass implements ExternalClass {
//..
//inject Environment to get property or via #Value as usual
//..
}
create this class in your project
#Component public class IOC implements ApplicationContextAware {
private static ApplicationContext ctx;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.ctx = applicationContext;
}
public static ApplicationContext getCtx() {
return ctx;
}
}
then call
Environment environment = IOC.getCtx().getEnvironment();
in the create method to get your properties

How to get bean using application context in spring boot

I am developing a SpringBoot project and I want to get the bean by its name using applicationContext. I have tried many solution from web but could not succeed. My Requirement is that I have a controller
ControllerA
and inside the controller I have a method getBean(String className). I want to get instance of registered bean. I have hibernate entities and I want to get an instance of the bean by passing the name of class only in getBean method.
Please help if someone know the solution.
You can Autowire the ApplicationContext, either as a field
#Autowired
private ApplicationContext context;
or a method
#Autowired
public void context(ApplicationContext context) { this.context = context; }
Finally use
context.getBean(SomeClass.class)
You can use ApplicationContextAware.
ApplicationContextAware:
Interface to be implemented by any object that wishes to be notified
of the ApplicationContext that it runs in. Implementing this interface
makes sense for example when an object requires access to a set of
collaborating beans.
There are a few methods for obtaining a reference to the application context. You can implement ApplicationContextAware as in the following example:
package hello;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
#Component
public class ApplicationContextProvider implements ApplicationContextAware {
private ApplicationContext applicationContext;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public ApplicationContext getContext() {
return applicationContext;
}
}
Update:
When Spring instantiates beans, it looks for ApplicationContextAware implementations, If they are found, the setApplicationContext() methods will be invoked.
In this way, Spring is setting current applicationcontext.
Code snippet from Spring's source code:
private void invokeAwareInterfaces(Object bean) {
.....
.....
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware)bean).setApplicationContext(this.applicationContext);
}
}
Once you get the reference to Application context, you get fetch the bean whichever you want by using getBean().
actually you want to get the object from the Spring engine, where the engine already maintaining the object of your required class at that starting of the spring application(Initialization of the Spring engine).Now the thing is you just have to get that object to a reference.
in a service class
#Autowired
private ApplicationContext context;
SomeClass sc = (SomeClass)context.getBean(SomeClass.class);
now in the reference of the sc you are having the object.
Hope explained well. If any doubt please let me know.
Even after adding #Autowire if your class is not a RestController or Configuration Class, the applicationContext object was coming as null. Tried Creating new class with below and it is working fine:
#Component
public class SpringContext implements ApplicationContextAware{
private static ApplicationContext applicationContext;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws
BeansException {
this.applicationContext=applicationContext;
}
}
you can then implement a getter method in the same class as per your need to get the bean. Like:
applicationContext.getBean(String serviceName,Interface.Class)
Using SpringApplication.run(Class<?> primarySource, String... arg) worked for me. E.g.:
#SpringBootApplication
public class YourApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(YourApplication.class, args);
}
}
As an alternative approach you can use ConfigurableApplicationContext to get bean of any class which is annotated with #Component, #Repository or #Service.
Let's say you want to get a bean of the class BaseComponent :
#Service
public class BaseComponent {
public String getMessage() {
return "hello world";
}
}
Now you can use ConfigurableApplicationContext to get the bean:
#Component
public class DemoComponent {
#Autowired
ConfigurableApplicationContext applicationContext;
public BaseComponent getBeanOfBaseComponent() {
return applicationContext.getBean(BaseComponent.class);
}
}
You can use the ApplicationContextAware class that can provide the application context.
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext ctx = null;
public static ApplicationContext getApplicationContext() {
return ctx;
}
#Override
public void setApplicationContext(final ApplicationContext ctx) throws BeansException {
ApplicationContextProvider.ctx = ctx;
}
/**
* Tries to autowire the specified instance of the class if one of the specified
* beans which need to be autowired are null.
*
* #param classToAutowire the instance of the class which holds #Autowire
* annotations
* #param beansToAutowireInClass the beans which have the #Autowire annotation
* in the specified {#classToAutowire}
*/
public static void autowire(Object classToAutowire, Object... beansToAutowireInClass) {
for (Object bean : beansToAutowireInClass) {
if (bean == null) {
ctx.getAutowireCapableBeanFactory().autowireBean(classToAutowire);
}
}
}
}
If you are inside of Spring bean (in this case #Controller bean) you shouldn't use Spring context instance at all. Just autowire className bean directly.
BTW, avoid using field injection as it's considered as bad practice.
One API method I use when I'm not sure what the bean name is org.springframework.beans.factory.ListableBeanFactory#getBeanNamesForType(java.lang.Class<?>). I simple pass it the class type and it retrieves a list of beans for me. You can be as specific or general as you'd like to retrieve all the beans associated with that type and its subtypes, example
#Autowired
ApplicationContext ctx
...
SomeController controller = ctx.getBeanNamesForType(SomeController)
Easy way in configration class call the BEAN annoted method . Yes u heard it right---- :P calling SpringBoot #Bean annoted method return the same bean from config .I was trying to call a logout in #predestroy method in config class from a bean and direcltly called the method to get the same bean .
P.S. : I added debug in the #bean annotated method but it didn't entered the method even when i called it.Sure to blame -----> Spring Magic <----
You can use ServiceLocatorFactoryBean. First you need to create an interface for your class
public interface YourClassFactory {
YourClass getClassByName(String name);
}
Then you have to create a config file for ServiceLocatorBean
#Configuration
#Component
public class ServiceLocatorFactoryBeanConfig {
#Bean
public ServiceLocatorFactoryBean serviceLocatorBean(){
ServiceLocatorFactoryBean bean = new ServiceLocatorFactoryBean();
bean.setServiceLocatorInterface(YourClassFactory.class);
return bean;
}
}
Now you can find your class by name like that
#Autowired
private YourClassfactory factory;
YourClass getYourClass(String name){
return factory.getClassByName(name);
}
Just use:
org.springframework.beans.factory.BeanFactory#getBean(java.lang.Class)
Example:
#Component
public class Example {
#Autowired
private ApplicationContext context;
public MyService getMyServiceBean() {
return context.getBean(MyService.class);
}
// your code uses getMyServiceBean()
}

Regarding spring container eagerly singleton design pattern

I have developed an utility class for spring which is a singleton which will provide the reference of container for the whole application , below is my class..
public class SpringUtility
{
private static BeanFactory factory ;
static
{try
{BeanFactory factory = new XmlBeanFactory(new FileSystemResource("Spring.xml"));
} catch(Exception e)
{
e.printStackTrace();
}
}
private SpringUtility()
{}
public static BeanFactory getBeanFactory()
{ return factory;
}}
Now please advise I want to convert it into style of eager singleton, Please advise how this could be achieved. please advise how this same class could be converted it in eager singleton design pattern such as the normal eager design pattern is ..
public class SingletonEager {
private final static SingletonEager INSTANCE = new SingletonEager();
private SingletonEager() {
}
public static SingletonEager getInstance() {
return SingletonEager.INSTANCE;
}
protected Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
}
similar way I want for spring one too please advise
If you want BeanFactory to grab beans from Spring context, then I'd suggest you to implement BeanFactoryAware, It would stay singleton & eagerly loaded
public class BeanManager implements BeanFactoryAware {
private BeanFactory beanFactory;
public Person getPerson(){ beanFactory.getBean(Person.class) ;}
}
And mark this BeanManager class as spring bean

What is the spring way to autowire factory created instances?

I have a controller which is supposed to create version dependend instances (currently not implemented).
#Controller
public class ReportController {
#Autowired
private ReportCompFactory reportCompFactory;
public ModelAndView getReport() {
I_Report report = reportCompFactory.getObject();
^^^^^<- no autowiring in this instance
}
...
}
The Factory looks like this:
#Component
public class ReportCompFactory implements FactoryBean<I_Report> {
#Override
public I_Report getObject() throws BeansException {
return new ReportComp();
}
#Override
public Class<?> getObjectType() {
return I_Report.class;
}
#Override
public boolean isSingleton() {
return false;
}
}
The created instances fields (#Autowired annotated ) are not set.
What should I do, is FactoryBean the right interface to implement?
I would prefer a solution which doesn't involve xml-configurations.
The component itself:
ReportComp implements I_Report {
#Autowired
private ReportDao reportDao;
^^^^^^^<- not set after creation
...
}
}
Spring doesn't perform autowiring if you create your objects. Here are a few options
define the bean to be of scope prototype - this will make the factory redundant (this is applicable in case you simply want instantiation in the factory)
inject the ReportDao in the factory, and set it to the ReportComp via a setter
inject ApplicationContext in the factory and do ctx.getAutowireCapableBeanFactory().autowireBean(instance)

Categories