I want to retrieve from my spring context all beans that are of a certain class (or subclass). But this only detects beans that are specifically defined by xml. Beans that are defined by annotations, such as #Serviceare not detected here. (Although inside the app they are detected, initialized, and autowired perfectly).
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext("*-context.xml");
Map<String, DataUpdater> beans = ctx.getBeansOfType(MyClass.class, true, true);
// why are beans missing?
I have seen similar problems and I never got getBeansOfType() to work correctly. My solution:
#Autowired
public void setMyClasses( List<MyClass> beans ) {
...
}
Spring will collect the list somehow and inject it. If you don't need to know when the list is injected, you can also inject it as a field:
#Autowired
private List<MyClass> beans;
You must search your beans also in
AnnotationConfigApplicationContext
If you want search in XmlContext and AnnotationContext you must combine them with
#ImportResource("classpath:xmlcontext.xml")
In annotated config
Or you can try implement ApplicationContextAware interface and search in Context provided by it.
Sorry, some stupid error... I was not properly loading my xml files, however beans were being instantiated as some background process was creating a parallel xml context with the correct files.
Related
I have such app conf in, jar which will be added to the classpath after startup:
#Configuration
#ComponentScan("com.transportexchangegroup.testConf")
public class AppConf {
}
How to load beans dynamically? I saw solutionsm when it is required to write and add bean definitions, but if we do not know everything about new beans and just want to load them automatically?
Class conf = jarService.loadClass("com.x.testConf.AppConf");
((AnnotationConfigServletWebServerApplicationContext) applicationContext).register(conf);
((AnnotationConfigServletWebServerApplicationContext) applicationContext).refresh();
As I see, refresh() turns off web app started locally from IDE.
Do you know any other solutions or what is wrong? Will this work for spring rest controllers from jar?
I'm not sure what do you mean "dynamically".
In general you can load beans if some condition applies, usually depending on the configuration. So you can do something like this:
application.properties: // or yaml it doesn't matter
feature.enabled=true
#Component
#ConditionalOnProperty(name="feature.enabled", havingValue="true", matchIfMissing="true" / "false") // matchIfMissing depends on whether you want the bean to be loaded if the property is not defined
public MyBean {
}
Some caveats:
If you have many beans that depend on "business" feature in order to avoid placing #ConditionalOnProperty you can do one of the following:
Define your own #Component annotation:
// runtime retention, place on class
#Component
#ConditionalOnProperty(...)
#MyFeatureComponent
... and use it in all the beans that define the feature:
#MyFeatureComponent
public class MyBean
{}
Use Java Configuration instead of annotations:
#Configuration
#ConditionalOnProperty(...)
public class MyFeatureConfiguration {
#Bean
public MyBean myBean(){return new MyBean();}
#Bean
public MyAnotherBean myAnotherBean(){return new MyAnotherBean();}
}
In this case you don't need to place any annotation on MyBean at all.
Spring also has a concept of profiles which is just the same, something that it under the hood implemented with these conditionals.
It allows however to define configuration files per profile, so you might want to read about #Profile annotation as well.
As for the bean definitions - this is way more advanced stuff, in general when spring loads it "recognizes" which bean should be loaded and in which order and for doing that it creates a bean definition before loading the bean. So if you hook into this process you can define your own bean definitions if you want and spring will create beans based on these definitions as well. So basically its a hook that allows altering the bean defitions / create new one during the startup process and hence affect the actual beans that will be loaded into the application context.
I doubt, but if you really need that, read about Bean Factory Post Processors in spring.
Given a Spring configuration that exclusively contains eager (non-lazy) singleton beans, i.e. the defaults, is it possible to have Spring throw an exception in the case where any of those beans is not injected anywhere? I'm essentially looking for a way to detect dead code in the form of Spring beans.
My question is somewhat similar to these.
http://forum.spring.io/forum/spring-projects/container/116494-any-tools-or-method-to-identify-unused-spring-beans
Spring Instantiation and 'unused beans'
How to detect unused properties in Spring
However,
I'm not interested in manually inspecting a graph or parsing log data.
I don't have the added complexity of multiple context files, overriding beans, bean post-processing, or xml. It's a simple, straightforward, annotation-driven configuration.
I'm using Spring Boot 1.2.6 which is several years newer than those questions (maybe new functionality exists).
Spring will certainly throw an exception if a necessary bean is missing. Can it also throw an exception in the opposite scenario where a bean is found but unnecessary?
Spring will certainly throw an exception if a necessary bean is
missing. Can it also throw an exception in the opposite scenario where
a bean is found but unnecessary?
TL/DR:
Spring does not support this (and probably never will).
Long version:
Detecting if a bean is used can be really hard.
First, lets define when does spring throw the "missing bean" exception.
During the initialisation of the spring context, spring creates the beans in the order in which it will allow for all dependencies to be satisfied (if possible). If a bean is missing a dependency, spring will throw an exception (as you said).
So, the exception is thrown during the spring context initialisation process.
Now, you could say that we could monitor this process and look for a bean that was not used as a dependency in any other bean.
The problem is that not all bean dependencies are defined during the spring context initialisation process.
Let's look at the following example:
First, we have a simple interface, DataService
public interface DataService {
String getData();
}
Now we have 2 spring beans that implement this interface:
#Service("firstDataService")
public class FirstDataService implements DataService {
#Override
public String getData() {
return "FIRST DATA SERVICE";
}
}
#Service("secondDataService")
public class SecondDataService implements DataService {
#Override
public String getData() {
return "SECOND DATA SERVICE";
}
}
Now, imagine that there is no bean that depends on these two beans directly. When I say directly, I mean there is no bean that depends on these beans via constructor-based, setter-based or field-based dependency injection.
Because of that, spring will not inject these beans inside any other bean during the context initialisation process.
Now, consider the following bean:
#Service
public class DataCollector {
#Autowired
ApplicationContext applicationContext;
String getDataFromService(String beanName) {
DataService ds = (DataService) applicationContext.getBean(beanName);
return ds.getData();
}
}
If I call the getDataFromService method of the DataCollector bean with "firstDataService" value for the beanName parameter, the method will return "FIRST DATA SERVICE" as a result.
If I call the method with "secondDataService", I will return "SECOND DATA SERVICE" as a result.
Now, when spring looks at the definition of DataController during context initialisation, there is no way to determine on which beans DataCollector depends on.
It all depends on the application logic, and the value that we use for the beanName parameter when we call the getDataFromService method.
Because of that, spring is not capable of determining if there is bean that is never used (because the bean usage can be dynamic, like in the case above).
I'd like to ask is there anyway to detect all beans have been instantiated in Spring framework ?
I'm using FileSystemXmlApplicationContext class of Spring library to load in my Spring configuration XML.
I do understand that I can get all beans after they are been instantiated in bean factory. My dumb solution is by using getBean(String name) method in Spring API and check against with all desired beans in the Spring configuration XML. If all desired beans can be found, I can infer that all beans have been instantiated.
The reason I don't prefer the dumb solution is anytime I update my configuration XML, I need to update my source code of checking against again. If this solution has more vulnerabilities, please feel free to point out.
Thanks your time and kindly suggestions
You can add a BeanPostProcessor to your context
class B1 implements BeanPostProcessor {
List beans = new ArrayList();
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
beans.add(bean);
return bean;
}
List getBeans() {
return beans;
}
...
What about using getBeansOfType(Object.class)?
You will get a map containing all name-bean pairs in the application context. The is also a version to include non singletons, but you will get top level beans only.
I have a java file "DatabaseMan.java" that helps connect to a database and connects helper functions. How can I make it such that it is created once for the life of my spring application, and I can call of its methods "getAllRows" for example, in each of my other resource classes?
Should I be declaring a bean in my Application.java or using some sort of annotation on my "DatabaseMan" class to indicate that it is "injectable"/"resusable"?
I see the following Spring3 example:
http://www.mkyong.com/spring3/spring-3-javaconfig-example/
The issue is, do I have to include this within every single resource:
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
HelloWorld obj = (HelloWorld) context.getBean("helloBean");
obj.printHelloWorld("Spring3 Java Config");
Is there a better way to get to the "HelloWorld" with less code and more annotation in Spring 4?
Remember, the ApplicationContext is a container to manage all your beans and their inter-dependencies. It is the entry point to your application. Once you've set it up, all the managed objects are linked up and ready to go.
Is there a better way to get to the "HelloWorld" with less code and more annotation in Spring 4?
It depends where you want to get it. If you want to get it from outside the ApplicationContext, then you need to do what you did. If you want to get into another bean, just inject it and the ApplicationContext will do the rest.
#Component
class SomeOtherBean {
#Autowired
private HelloWorld helloWorldBean;
// do something with it
}
I have a bunch of java custom tags that use spring managed beans.. since i cant find a way to inject into a custom tag, i created a helper class that provides static methods to "getTheObjectINeedBean()" for all the spring bean objects i need.. I do not like this approach at all.
i really want to be able to inject a spring managed bean into the custom tag
Is there a way? As far as my research goes, I understand there is no way to do this, because the custom tag is container managed
Thanks,
Billy
You are correct there isn't a simple way to use dependency-injection in jstl tags, because they are not managed by spring, and cannot be. However there are (at least) two workarounds:
#Configurable - aspectJ allows you to plug a weaver at load-time/compile-time, so that even objects that are not instantiated by spring can be spring aware. See here
You can create a base tag class for your project, and call an init(..) method from every doStartTag(..) method. There, you can get the ServletContext from the pageContext, and thus obtain the spring ApplicationContext (via ApplicationContextUtils). Then:
AutowireCapableBeanFactory factory = appCtx.getAutowireCapableBeanFactory();
factory.autowireBean(this);
Neither options are perfect as they require either some additional code, or some "black magic"
To expand on #Bozho's post, I have gotten this to work like so: (in spring 3.0 there is no ApplicationContextUtils that I could find)
public class LocationTag extends RequestContextAwareTag {
#Autowired
PathComponent path;
...
#Override
protected int doStartTagInternal() throws Exception {
if (path == null) {
log.debug("Autowiring the bean");
WebApplicationContext wac = getRequestContext().getWebApplicationContext();
AutowireCapableBeanFactory acbf = wac.getAutowireCapableBeanFactory();
acbf.autowireBean(this);
}
return SKIP_BODY;
}
}
The solution as described above works but some background and additional code snippets are, quite likely, useful.
1) The doStartTagInternal method is invoked from the doStartTag method.
2) I was forced to set the pageContext first before invoking the doStartTag
3) I did a lookup of the bean as opposed to the autowiring. To me this seems more straightforward: (YourBeanProxy) autowireCapableBeanFactory.getBean("yourBeanName")
Hopefully this additional info is useful.