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.
Related
Anyone can explain how Spring defines the bean creation mechanism when create a bean which depends on a list of other beans? It would be good to show the part of Spring specification on how it's defined.
Code like:
public interface Test {
}
#Service
public class TestImpl1 implements Test{
}
#Service
public class TestImpl2 implements Test{
}
public class TestContainer {
List<Test> testList;
TestContainer() {
testList = new ArrayList<>();
}
public void addTest(Test test) {
testList.add(test);
}
}
then
#Bean
public TestContainer testContainer(List<Test> testList) {
TestContainer testContainer = new TestContainer();
for (Test test : testList) {
testContainer.addTest(test);
}
return testContainer;
}
Question is really: when creating bean for TestContainer, how does Spring figure out what should be in List testList?
This looks like what you are looking for:
https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-factory-class
You haven't specified what exactly do you want to know about bean creation but here is the minimum you should know. By default all beans are singleton scoped (only created once during the container life-cycle and for all the subsequent request the same instance is returned). All singleton scoped beans are created eagerly. If the singleton bean is dependent on some other beans (needs them for instantiation) then those other beans will be instantiated with it/right before it, doesn't matter whether they are singletons or not, marked as lazy or not.
This is part of the spring documentation I think on their website. Look for it. The whole spring documentation is worth to read, even if it is a long read (https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#spring-core)
But mostly, spring would first read all the XML, anotations and other source of config data and get a list of beans to init. Then it would get a list of dependencies between beans constructing kind of a tree. As the dependencies need to be initialized first, there an obvious orderining for initialization.
On top, you can set your own priorities for beans so that you can get some beans initialized first or last for example.
For your specific case, spring will inspect the code source as well as use the Java reflection API to figure out you want a collection of interface Test implementations. So spring would look for ALL the defined bean that match and return them that not more complex than that.
It's mostly using the concepts of graph data structure where the beans become the nodes of the graph and they are resolved using topological sort.
Situation: You have a metric registered in Spring Boot via a MeterBinder. Maybe it one of the auto-configured metrics like jvm.gc.pause1 or it could be a custom metric of your own. But one day, you start your application and it is missing. It isn’t reported, it doesn’t show in Actuator, it’s just gone.
Root Cause: Probably your code or a library you are using is injecting the MeterRegistry. There are lots of legitimate reasons to do this, so don’t blame yourself. But injecting the MeterRegistry means that it will be created and initialised before all your beans are created, including possible MeterBinders.
It is also possible nothing is injecting MeterRegistry, but Spring has decided to create it before the MeterBinders for some other reason. Whatever the case, MeterBinders will stop working for you and there isn’t much you can do about it.
My solution is to create my own post-processor:
#Component
class FixMeterBinders implements BeanPostProcessor {
#Autowired
ObjectProvider<MeterRegistry> meters;
public Object postProcessAfterInitialization(Object bean, String beanName) {
if(bean instanceof MeterBinder) {
((MeterBinder)bean).bindTo(meters.getObject());
}
return bean;
}
}
There is a big downside to this approach: If Spring’s post-processor is working as intended, each MeterBinder will be run twice, so you need to make sure the work they do is idempotent.
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 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.
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.