I am using spring.factories to set bootstrap context
org.springframework.cloud.bootstrap.BootstrapConfiguration=sompePackage.MyBootstrapConfiguration
I was following what is mentioned in this link
https://cloud.spring.io/spring-cloud-commons/multi/multi__spring_cloud_context_application_context_services.html
I noticed 2 things hope you please can help me with
1- I cannot spy on any bean that is created through the bootstrap context, in other words, if I create a bean of type x in MyBootstrapConfiguration, spying on that bean with #SpyBean is not working, I can spy on all other beans but the bootstrap context ones (I am using springboottest)
2- If I inject ApplicationContext somewhere and print all the defined beans, i cannot see the beans that were created in the bootstrap context, in other words, the bean x that is created in MyBootstrapConfig is not there. However, #Autowired is working fine and the bean is injected correctly.
My questions are:
1- How can i spy or mock the bootstrap context beans?
2- If i cannot find these beans in ApplicationContext, where are they?
Thanks,
try to put break point where you are creating your bean and run with debug mode, then you will find out whether your bean is created or not
You could define your own context for the test scope you are trying to run:
This would look something like:
public class TestApplicationContext implements ApplicationContextAware {
private static ApplicationContext context;
#Override
public void setApplicationContext(final ApplicationContext context) throws
BeansException {
TestApplicationContext.context = context;
}
public static Object getBean(final String beanName) {
return context.getBean(beanName);
}
}
Then you can create a bean for the context in a #Configuration annotated class.
#Bean
public TestApplicationContext testApplicationContext() {
return new TestApplicationContext();
}
Then you can easily reference whatever bean you need by simply:
TestApplicationContext.getBean("someBean");
Related
I'm using a configuration class that uses dynamic bean registration:
#Configuration
public class ConfigClass {
#Autowired
private GenericApplicationContext applicationContext;
#PostConstruct
private void init() {
System.out.println("init");
applicationContext.registerBean("exService", ExecutorService.class, () -> Executors.newFixedThreadPool(10), bd -> bd.setAutowireCandidate(true));
System.out.println("init done");
}
}
If I try to autowire the bean, application startup fails with error Field exService in com.example.DemoApplication required a bean of type 'java.util.concurrent.ExecutorService' that could not be found.
From the logs I can see that the init method on config class wasn't called before the error as the two system out statements were not printed out.
However, when I use applicationContext.getBean(ExecutorService.class) it does work without any issues.
Anyway I can get the bean to Autowire?
I'm deliberately not using the #Bean annotation because I need to register the beans dynamically based on certain conditions.
It could be because you are registering your bean in the middle of the context initialization phase. If your target bean initializes and auto-wires ExecutorService before ConfigClass #PostConstruct is invoked there simply is no bean available.
You can try forcing the initialization order:
#Component
#DependsOn("configClass")
public class MyComponent
#Autowired
private ExecutorService executorService;
However it would be cleaner to register a bean definition using BeanFactoryPostProcessor with BeanDefinitionBuilder:
#Component
public class MyBeanRegistration implements BeanFactoryPostProcessor {
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory bf) {
BeanDefinitionRegistry reg = (BeanDefinitionRegistry) bf;
reg.registerBeanDefinition("exService",
BeanDefinitionBuilder
.rootBeanDefinition(ExecutorService.class)
.setFactoryMethod("newWorkStealingPool")
.getBeanDefinition());
}
}
You can do like this:
#Resource
#Lazy
private ExecutorService executorService;
It works.
Actually, I wrote the small infrastructure that deals with such issues. Here is the idea how to do this:
Create a class (lets call it MyClass) that incapsulates ExecutorService.class as a property and declare it as Bean (#Component). Even before that create an Interface (Lets call it MyInterface) that your new class would implement
Create a factory class (Lets call it MyFactory) with method MyInterface getInstance(String) that returnce an instance of your interface. In that factory crate a static property Map[String, MyInterface] and public static method that allows you to add instances of the interface to this map
In MyClass create a constructor that at the end will place newly created instance of itself into that map in the factory with the key of your class name ("MyClass")
Now The trick is that when Spring starts and initializes it creates all its beans. As your MyClass will be created its constructor will place its instance into a factory. So now anywhere in your code you can call:
MyInterface myInterface = MyFactory.getInstance("MyClass");
And you get your bean without worrying about instantiating it. Spring already did it for you. Big extra bonus is non-intrucivness - you don't have to explicitely work with Spring classes
I have spring application alongside (jersey 2.6 classes and ) servlets .
I need to get Spring bean(s) from jersey/non spring context,
Similar question suggested to get context in a static wrapper of context
public static ApplicationContext getContext() {
return context;
}
How can I be sure the context is already loaded or not null?
If I can't, how should I wait/check until it spring context is loaded?
In case of calling from jersey context or calling bean from a simple HttpServlet code
EDIT
Jersey is working fine using jersey-spring3 dependency jar, so my question is only about Servlets out of Spring control
EDIT 2
The application is loading spring different than #entpnerd suggested article
It register a Servlet implementing a WebApplicationInitializer
public class MyWebAppInitializer implements WebApplicationInitializer {
But also have DispatcherServlet configured in web.xml
How can the DispatcherServlet loaded only after Spring loaded?
Because we add Autowiring capabilities on its init method:
WebApplicationContextUtils.getRequiredWebApplicationContext(config.getServletContext())
.getAutowireCapableBeanFactory().autowireBean(this);
Is adding a timeout before serving requests is the most prefer solution or is there a tweak in class loading that can take care of it?
EDIT 3
I found answers and answers of injecting, but not why Spring is loaded before Servlet.
The idea is quite simple, although the actual implementation may vary depending on an exact way of Spring boot and Jersery initialization.
An idea:
Spring boot, as being a purely runtime framework, is all about proper loading the application context (from the question standpoint).
So, bottom line, when it's loaded there is an application context somewhere in memory, and its possible to access beans from this application context.
Now, since you say that Jersey is not spring/spring-boot driven, this application context has to be reachable from some kind of static global variable by Jersey, it's quite ugly but should work.
So the idea has two steps:
Put an application context reference to some static holder accessible from Jersey.
Read this value in some infrastructure level code from Jersey component.
A Possible Implementation
Technically step one can be done by implementing some kind of spring boot listener that will store application context in some kind of singleton:
enum ApplicationContextHolder {
INSTANCE;
private ApplicationContext ctx;
void setApplicationContext(ApplicationContext ctx) {
this.ctx = ctx;
}
ApplicationContext getCtx() {
return this.ctx;
}
}
// and a listener (spring boot provides many ways to register one, but the
// implementation should be something like this):
// The main point is that its managed by spring boot, and hence and access to
// the application context
class StartupListener implements ApplicationListener<ContextRefreshedEvent> {
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
ApplicationContextHolder
.INSTANCE
.setApplicationContext(event.getApplicationContext());
}
}
Now the step 2 is:
class MyJerseyOrWhateverComponentThatWantsToAccessApplicationContext {
public void foo() {
ApplicationContext ctx = ApplicationContextHolder.INSTANCE.getCtx();
...
ctx.getBean(...);
}
}
So a viable solution for this could happen in two stages:
A Spring bean gets the ApplicationContext instance and sends it to a static singleton outside of the Spring context.
Your standalone servlet gets the ApplicationContext instance from the static singleton and verifies that the right beans have been loaded.
Consider the following code as an example:
SpringMetaBean.java
// #Component so that it's part of the Spring context
// Implement ApplicationContextAware so that the ApplicationContext will be loaded
// correctly
#Component
public class SpringMetaBean implements ApplicationContextAware {
private ApplicationContext appCtx;
public setApplicationContext(ApplicationContext appCtx) {
this.appCtx = appCtx;
}
// #PostConstruct so that when loaded into the Spring context, this method will
// automatically execute and notify ApplicationContextHolder with a reference to
// the ApplicationContext
#PostConstruct
public void setup() {
ApplicationContextHolder.set(this.appCtx);
}
}
ApplicationContextHolder.java
public class ApplicationContextHolder {
// ensure the reference is thread-safe because Spring and standalone Servlet will
// probably be running on different threads.
private final AtomicReference<ApplicationContext> appCtxContainer = new AtomicReference<>();
public void set(ApplicationContext appCtx) {
this.appCtxContainer.set(appCtx);
}
public ApplicationContext get() {
return this.appCtxContainer.get();
}
}
MyStandaloneServlet.java
public class MyStandaloneServlet {
// my request handler method
public void getResponse(HttpServletRequest rq) {
ApplicationContext springAppCtx = ApplicationContextHolder.get();
// if not null, we know that Spring has been loaded and we can dig into the
// application context.
}
}
I have this requirement,
My framework is in a way that it reads the class name from the configuration file as a string and I would like to use methods inside that class.
Obvious solution is to use reflection,
I have used reflection and able to call methods I wanted, but the problem is the variables inside the target class are not autowired. I understand I am not letting spring to autowire the fields by using reflection (Spring with class.forname()).
Is there a way for me to autowire the class variables instead of creating new instance? Or Am I in a deadlock situation?
Option 1: If you have access to the current Spring ApplicationContext, you could do this as follows:
String className = <load class name from configuration>
Class<?> clazz = Class.forName(className);
ApplicationContext applicationContext = <obtain Spring ApplicationContext>
applicationContext.getBean(clazz);
This of course means that the class whose instance you wish to load is a Spring managed bean. Here is a concrete example:
package org.example.beans;
#Component
class Foo { ... }
#Component
class SpringApplicationContext implements ApplicationContextAware {
private static ApplicationContext CONTEXT;
#Override
public void setApplicationContext(final ApplicationContext context) throws BeansException
CONTEXT = context;
}
public static <T> T getBean(String className) {
return CONTEXT.getBean(Class.forName(className));
}
}
Option 2: You could manually create an instance of the required class and then ask Spring to populate its dependencies.
This again requires access to the ApplicationContext. For example:
T object = Class.forName(className).newInstance();
applicationContext..getAutowireCapableBeanFactory().autowireBean(object);
It's possible. Have a look at how Spring's JUnit test integration does it. That's in the spring-test module.
The runner is SpringJUnit4ClassRunner, but the actual injection code is in DependencyInjectionTestExecutionListener.injectDependencies. It uses a Spring context that implements AutowriteCapableBeanFactory.
The code to do this looks like below. Note that this assumes that you have used annotations to indicate which fields need to be autowired.
Object bean = ...;
AutowireCapableBeanFactory beanFactory = ...;
beanFactory.autowireBeanProperties(bean, AutowireCapableBeanFactory.AUTOWIRE_NO, false);
beanFactory.initializeBean(bean, "beanName");
I need to fetch a singleton bean from same ApplicationContext twice in 2 different classes.
Example snippet :
CLass A {
public void foo(){
ApplicationContext context = new ClassPathXmlApplicationContext("common.spring.xml");
MyParametrizedSingletonClass myParametrizedSingletonClass = (MyParametrizedSingletonClass) context.getBean("myParametrizedSingletonClass");
// do more stuff..
}
CLass B {
public void bar(){
ApplicationContext context = new ClassPathXmlApplicationContext("common.spring.xml");
MyParametrizedSingletonClass myParametrizedSingletonClass = (MyParametrizedSingletonClass) context.getBean("myParametrizedSingletonClass");
// do more stuff..
}
Since MyParametrizedSingletonClass is a singletom it if its constructor is called more than once for same constructor arguments it throws error.
How do I cache and reuse ApplicationContext with spring?
You are creating two different context, so even if bean is singleton it will create single instance per context,
if you want to cache application context you can create a class and provide singleton instance of application context
Autowire the bean.
By default the spring injects the autowired beans into required classes and these beans are not created an new everytime. They are singleton by default.
in common.spring.xml file for the bean name myParametrizedSingletonClass add the scope singleton to it as a parameter while defining the bean in the xml file
I have a stateful Spring bean. How can I enforce its usage scope to prototype in my application?
How can I prevent another developper on my project of injecting this bean with the singleton scope?
I know you can configure scope either via annotation or via the xml configuration. Of what I have seen, when using Spring 3, the scope configured by annotation gets overriden by the scope defined manually in the xml. How can I enforce my scope, thru configuration or programatically, so my bean will never be used as a singleton?
I thought about inspecting the bean scope on the startup of the application, but it doesn't sound like an elegant solution.
This is not elegant, but AFAIK this is the only way to achieve what you are looking for
public class MyStatefulBean implements InitializingBean, ApplicationContextAware, BeanNameAware {
private String myName;
private ApplicationContext context;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.context = applicationContext;
}
#Override
public void setBeanName(String s) {
this.myName = s;
}
#Override
public void afterPropertiesSet() throws Exception {
if(this.context.isSingleton(this.myName))
throw new RuntimeException("Bean CANNOT be singleton");
}
}
Document it? There's no way for it to know if someone is keeping a reference to the bean and reusing it or sharing it across threads when they should have been using getBean() to get the prototype.
Spring cannot stop your peers from writing code that is simply incorrect, which is all that such a usage would be.
If you don't want to rely on the API user doing what's expected of them, expose the bean via a factory.