How can I get the bean definitions without actually creating the beans? - spring

For static analysis of my Spring config, I need just the bean definitions - actually creating the beans would cause problems because some need a (properly initialized) database.
Is there a way to prevent the AnnotationConfigApplicationContext to create any beans? Instead, it should just load and analyze the config and stop.

you could implement the BeanDefinitionRegistryPostProcessor interface. in the postProcessBeanDefinitionRegistry method you have access to BeanDefinition's
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// ...
}
#Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
registry.getBeanDefinition("myBean");
}
}

Related

setApplicationContext(ApplicationContext applicationContext) never called

I'm trying to get the Spring application context and then call its method getBean("beanName") to get a specific bean but I'm having a null pointer exception indicating that the context is null. When I put a breakpoint inside the setApplicationContext() method, I found out that this method is never called which is weird since this method should be called after spring finishes beans instantiation. I looked for some similar questions here but none worked for me.
this is my code:
public class SpringApplicationContext implements ApplicationContextAware {
private static ApplicationContext CONTEXT;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
CONTEXT = applicationContext;
}
public static Object getBean(String beanName){
return CONTEXT.getBean(beanName);
}
}
Set the ApplicationContext that this object runs in.
Normally this call will be used to initialize the object.
The ApplicationContext object to be used by this object.
Add #Component.
#Component
public class SpringApplicationContext implements ApplicationContextAware {
private static ApplicationContext CONTEXT;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
CONTEXT = applicationContext;
}
public static ApplicationContext getApplicationContext(){
return CONTEXT;
}
}
Use ApplicationContext.
TheBeanInstance bean = SpringApplicationContext.getApplicationContext().getBean(requiredType);
ApplicationContextAware

Spring: Is it possible to lazy load all Spring Beans without #Lazy

I am looking to lazy load all spring beans when running integration tests that utilize #ContextConfiguration. Ideally I would be able to apply this lazy loading in one place and have it applied to any beans that are loaded via the #ContextConfiguration annotation.
Yes it is.
You can do this using BeanDefinitionRegistryPostProcessor/BeanFactoryPostProcessor.
#Configuration
static class LazyBeans implements BeanDefinitionRegistryPostProcessor {
#Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry bdr) throws BeansException {
for (String name : bdr.getBeanDefinitionNames()) {
final BeanDefinition beanDefinition = bdr.getBeanDefinition(name);
if (beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION) {
beanDefinition.setLazyInit(true);
}
}
}
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory clbf) throws BeansException {}
}

How to search and auto-register all beans under a specific package

I have x number of beans under some base-package say com.mypackage.basepackage.
What I am trying to do is to auto-scan this package and register all the beans to ApplicationContext with BeanDefinitionRegistryPostProcessor.
Here is how I am trying to do this.
public class BeanRegistrar implements BeanDefinitionRegistryPostProcessor
{
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException
{
}
#Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException
{
//loop n-number of times and register all the scanned beans.
BeanDefinition beanDefinition = new RootBeanDefinition(scannedbeans.class, Autowire.BY_TYPE.value(), true);
registry.registerBeanDefinition("beanName", beanDefinition);
}
}
What I want is to loop on com.mypackage.basepackage , look for beans and register them.
I know I can scan basepackage with
<context:component-scan base-package="com.mypackage.basepackage" />
use ClassPathBeanDefinitionScanner
http://docs.spring.io/spring/docs/3.0.x/javadoc-api/org/springframework/context/annotation/ClassPathBeanDefinitionScanner.html

why invoking a service in my servlet gives me an NPE (spring)

I have defined a service in Spring
#Service("StockageService")
public class StockageServiceImpl implements StockageService{
}
with
public interface StockageService extends Serializable {
}
And I need in a servlet to invoke this service
So I wrote
public class SpringApplicationContextListener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent sce) {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
sce.getServletContext().setAttribute("applicationContext", ac);
}
public void contextDestroyed(ServletContextEvent sce) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
}
And
public class handler extends HttpServlet {
private String message;
private StockageService stockageService;
#Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
ApplicationContext ac = (ApplicationContext) config.getServletContext().getAttribute("applicationContext");
this.stockageService = (StockageService)ac.getBean("StockageService");
}
The problem is that I get a NPE at the last mentionned line
(StockageService)ac.getBean("StockageService");
Where could I have made a mistake ?
First, thanks ankur-singhal for having taken the time to answer my question
I understand the reasonnement of your answer but it does not work when I invoke
ApplicationContextUtils. getApplicationContext().getBean("StockageService");
So I used a trick which works but I do not understand very well
I override the init in my servlet as it follows
#Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this,
config.getServletContext());
}
and I have to put a
#Autowired
private StockageService stockageService;
in the servlet and it works
It seems that ApplicationContext itself is comming as null.
Look at below code and try make use of this.
ApplicationContextUtils.java
We will create the following utility class, it implements ApplicationContextAware and provides the setApplicationContext which will be invoked by spring container and the applicationContext will be passed by it. We store it in a static variable and expose it through a get method so that it can be accessed all through the application.
You can set the same while creating ApplicationContext
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class ApplicationContextUtils implements ApplicationContextAware {
private static ApplicationContext ctx;
#Override
public void setApplicationContext(ApplicationContext appContext)
throws BeansException {
ctx = appContext;
}
public static ApplicationContext getApplicationContext() {
return ctx;
}
}

Access spring component from servlet

I have a controller (for example. MyManager) where I invoke method (for example myMethod() ) of component class (bean), for example MyComponent. I have I servlet where I want to invoke myMethod() . In servlet I have annotated MyManager by #Autowired annotation , despite this I got NullPointerException. I saw this kind of topic but it is not useful for me. For imagination I write little code :
public class myClass extends HttpServlet {
#Autowired
private MyComponent component;
public void init(ServletConfig config) throws ServletException{
super.init(config);
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
}
protected void doGet(HttpServletRequest req,HttpServletResponse res) throws ... {
List<MyObject> objects =component.myMethod(); // Here is the problem, component is null
}
}
}
I make Spring configuration file "context.xml" and I got bean (component) object, but now I have problem with injected EntityManager in bean object. Now it is null , can anyone help me to solve this problem ? Also update init() method.
public void init(ServletConfig config) throws ServletException{
ApplicationContext con = new ClassPathXmlApplicationContext("context.xml");
component = (MyComponent) con.getBean("myBean");
}
You cannot autowire dependencies like that because Servlets are not Spring Beans. You need to do something like the following:
#Override
public void init() throws ServletException {
super.init();
ApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
component= applicationContext.getBean(MyComponent.class);
}
Also drop the #Autowired annotation from component

Resources