I am not a native English speaker...there maybe some errors in expression, please forgive me..
//import org.springframework.context.ApplicationContext;
//in a #Component class
#Autowired
private static ApplicationContext context
I hope that the above code can work, the field variable context can get the applicationcontext of the springboot application.. but actually it doesn't work.
I have searched for some means to realize this aim, but I think them complex, for example ,implementing ApplicationContextAware...
Please think of factory pattern. Some of the instances which the factory class may return have field variable which need #Autowired, so they have to be managed by Spring, and the factory has to return applicationContext.getBean(...), can't use return new ... or return Class.forName(...)....
I think the factory pattern should be used widely, which I want use to prove that it is meaningful to get the the instance of ApplicationContext of a spring-boot application simply just like the top code...And why it's still complex now?
Thanks.
You can think of Spring as a factory that can create objects for you. These objects are called 'Beans' in spring world.
So, usually the beans do not have an access to the factory that has created them.
For example, think about the factory that produces "cars" like Toyota of Ford.
In terms of OOP, you can "buy" or "drive" the car (an instance of the class Car), but that factory creates these instance (does new Car). Since the actual car is managed by spring, its a bean. Now if you describe the car as a class in Java, its not reasonable to have something like this, right?
#Component
public class Car {
...
private CarFactory carFactory;
}
So Spring already "hides" the factory for you and you have a class Car "clean" of the boilerplate.
Now, as for the application context itself. It is actually that factory - and as our colleagues have already stated, you shouldn't really use the application context reference in your beans.
If you really need it, you can inject the application context but then it should not be static, and in general its better to access it from the #Configuration classes that are supposed to provide the way to create beans in more flexible ways.
Related
I am learning Spring Boot and have quite a theoretical question. In this Udacity Example the
model class is initiated manually:
ChatMessage newMessage = new ChatMessage();
Is it good practice?
I will elaborate further on this. Let's say I have a DateUtil class that does some date conversions, should I register it using #Component annotation or manage its dependency myself (DateUtil dateUtil = new DateUtil())?
So the main summarized question: How to know when to use component annotations and when to initialize classes manually?
Thanks a lot!!!
The answer to the first question is, yes, it's still okay, because beans are assumed to be singletones, although not always. In this case, it makes no sense to mark the ChatMessage class as a bean, since instances of this class will be created many times and it is absolutely unclear what benefit will be obtained if they are all beans and are located in the application context.
Answer to the second question: I think the DateUtil class should be instantiated in the usual way, because it looks like a regular utility class like StringUtils. Perhaps you should make its methods static and then you won't have to instantiate it at all. But if this is a complex class that contains business logic and / or is initialized with some data received from outside the application when it starts and this object of this class is used in other classes of the application, then it may be worth making it a bean.
The answer to the third question: it is difficult to give an unambiguous answer. Beans are worth creating when you want to achieve an inversion of control and not depend on the class you are injecting. Declaring a class as a component so that its instances become beans must make sense, bring an advantage to the design of the application.
You need experience with Spring applications to understand when to make beans. Take a look at some well-known Spring applications to understand in which case and which class instances are beaned.
As I know, when you create class with #Component (I like use #Service), Spring will create bean inside IoC. Then you can use that bean by #Autowired, with #Component you create only one instance, that will be shared all over the application. When you use 'new' method to create object, you create object by yourself. Check more info in bean scope doc.
I am trying to apply ioc into a school project. I have an abstract class Application without any field
public abstract class Application {
abstract public void execute(ArrayList<String> args, OutputStream outputStream, InputStream inputStream) throws IOException;
}
And I will call the concrete class that extends Application by
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Application app = (Application)context.getBean(appName);
My questions are:
Is it a bad practice to initialise a bean without any field (or all the fields are constants) using Spring?
As there is no dependency to other classes in Application, are we still consider this as a dependency injection or IOC? If no, what is the difference between this and a normal factory pattern? It seems that what Spring does here is simply matching the class and initializing it.
UPDATE
Here is the code snippet of the class where the instance of Application is needed.
String appName = argument.get(0);
Application app = ApplicationFactory.getApplication(appName);
ArrayList<String> appArgs
= new ArrayList<String>(argument.subList(1, argument.size()));
app.execute(appArgs, outputStream, inputStream);
Further questions:
in my code the class X will call the instance of Application by specifying a concrete application class name. In this case, it is still not possible for Spring to inject the dependency to Application, right? As what I need is a concrete class but not Application itself.
if Application does have fields but these fields are initialsed somewhere higher than X (X receives them as inputs and passes them to Application), can I use DI in this case?
Is it a bad practice to initialise a bean without any field (or all the fields are constants) using Spring?
No, its totally fine. Its true that you won't be able to "take advantage" of the automatic dependency injection mechanisms provided by spring (because obviously there are no dependencies in the class Application in your example), however spring can still:
Make sure that the Application as a singleton "obeys" the rule of being a single instance in the whole application context. For "manually" maintaining singletons you need to write code. Spring does it for you.
Manages the lifecycle of the object. Example, Spring has "postConstruct"/"preDestroy" methods that can can be run in the appropriate time and make example any custom code of the class Application.
If this class does some heavy-lifting (even without spring) than it can make sense to define it "lazy" so that the initialization of this instance will actually be done upon the first request to it.
Sometimes you/or spring itself will create a proxy of this class in runtime (for many different reasons, for example this aforementioned lazy functionality, but there are also other use cases). This is something that spring can do for you only if it manages the Application and not if its defined outside the spring.
Ok, you don't have dependencies in the application, This means that this Application class has some useful methods (at least on method, like public void foo() for
simplicity). But this in turn means that there is some class (lets call it X) that calls this method. So this class has an instance of Application as a dependency. So now the real question is who manages this class X. Probably it makes sense to manage it in Spring as well, and then you will benefit of the Dependency Injection mechanisms in this class X only because Application is also managed by Spring. In general Spring can inject dependencies only if these dependencies are managed by Spring.
I know, this last paragraph may sound vague given the use case you've presented, but you've got a point, for example in real application people make an initial bootstrapping in very certain places. Usually also people use spring boot that kind of encapsulates this kind of things for you.
As there is no dependency to other classes in Application, are we still consider this as a dependency injection or IOC? If no, what is the difference between this and a normal factory pattern? It seems that what Spring does here is simply matching the class and initializing it.
So as you see, the concept of DI container goes far beyond of what the factory pattern has to offer. In short, factory pattern only specifies the way to create the objects. Spring on the other hand, not only creates the objects but also manages them.
First, I very strongly suggest that you use Spring Boot instead of manually manipulating Spring at a low level like this.
It's perfectly ordinary to use beans that don't have their own fields for settings, but this is usually so that other beans can have pluggable strategies or providers and you can define in your application setup which to use.
If your Application class doesn't need anything else, then there really is not much advantage to Spring. Most real-world programs get complicated soon, however, and that's where it becomes useful.
Finally, you should almost never pass ArrayList as a parameter; use List instead. In the code you showed, however, if you have String[] args, you couldn't say app.execute(Arrays.asList(args), System.out).
I have query on bean instantiation in spring.
According to the Spring Reference document, in the section 'Instantiating beans", it is mentioned that
" container itself directly creates the bean by calling its constructor reflectively, somewhat equivalent to Java code using the new operator " .
This implies that Spring container uses reflection to create beans.How ever in few scenarios, container also uses static factory method on a class to create a bean. The only case I knew container use static factory method is "WHEN THE CONSTRUCTOR IS PRIVATE".
So my doubt is, since container uses Reflection to create objects, it should be able create objects of classes of even private constructor as well.Why should container rely on static factory method ?
Or are there any other uses of calling static factory method to create beans ?
Thanks in advance. If there is any fundamental understanding required for me, kindly suggest so.
Yes you are right Spring can invoke private constructor if you provide right arguments while defining the bean in configuration. But on question that comes to my mind is why would you do that if that bean is not meant to be instantiated?
It would be the case only say when you have helper class with static method or singleton etc. So it wont make sense to instantiate those classes.
But in your case, it's factory and you might be getting the object back by calling static method (accessing Static method/field doesn't necessarily need Object to access field/method) say getShape and you might be getting different shape based on parameter's that you might supply.
We sometimes need to use a class which was not designed for Spring and need to be instantiated via static factory method and Spring provides us with such possibility.
Today, we found this pattern in our code:
class Foo {
private List<String> errors;
public void addError(String error) { ... }
public List<String> getErrors();
}
While the code seems to work, this is a singleton Spring bean and it's injected in several independent places and the consumers of the bean assume that they each have their own list of errors. So this introduces subtle bugs.
The obvious solution is to educate developers to avoid this kind of error but I was wondering if there is a static or runtime code analysis tool which can find this kind of bug.
For example, a bean postprocessor could analyze the bean before it's returned and look for private fields that aren't #Autowired.
After pouring some more brains (ours and other peoples) on this, we came up with this approach:
Install a BeanPostProcessor which makes sure that all singleton beans (i.e. where the scope in the bean definition is Singleton) have the custom annotation #Stateless on the actual bean type.
We chose a custom annotation instead of reusing #Singleton since we need this functionality elsewhere, too.
If the annotation is missing, the factory throws an error.
In a unit test, we use ClassPathScanningCandidateComponentProvider with out custom annotation to locate all classes on the classpath. We can then do the complex and expensive tests to make sure the bean has no state that changes after the initial configuration (i.e. after the autowiring has happened).
The second step could become a little bit easier if we moved the autowired fields into the constructor but we don't like methods that take many, many arguments. It would be nice if Java or an IDE could generate builders from the bean code. Since that's not the case, we stick to autowired fields and/or setters.
You could create a JUnit test that would load your app config.
This could combine ListableBeanFactory from here :
Can I dynamically create a List by scanning the beans in a spring configuration file?
with the 'isSingleton' check here :
How to enforce a prototype scope of Spring beans
i.e. list all the beans in the app context, then check to see which are singletons.
This would let you find all singleton beans...although it wouldn't really prevent your error case where someone treats one of these singletons as if it were not.
I want to be able to call Interfaces in my class, but have spring instantiate them with the right implementation class behind the scenes.
I.e. Normally you can do:
IClass clz = new Class();
I want to have the line IClass clz; preferable in the middle of a method (or as one of the attributes if it can't be done), where clz is instantiated to the class I want by Spring.
The reason I'd like to do it this way is because I want to be able to be able to change which implementation I want to use simply by editing the context files.
Even better, would be knowing how to do the above with class contructors that expect parameters. i.e. new Class(ar1, arg2);
I hope this makes sense. Any help would be much appreciated.
You can make your class implement BeanFactoryAware and then Spring will inject the bean factory in your class. If you then want to get an instance of a class implementing your interface you say something like:
beanFactory.getBean(IClass.class);
If there are multiple beans that implement the same interface you will have to resolve by name. To create a new object each time you ask this, set the bean scope of the bean you're asking for to "prototype".
You can include code such as:
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
IClass clz = (IClass) context.getBean("beanName");
Not saying this is better per se than Gerco's answer btw, just it's an option, depending what you want to do.
You can also implement the ApplicationContextAware interface: I've found that using ApplicationContext gives me beans with filled-in properties, e.g. if you have an app.properties file which contains key/value property pairs which you expect to be resolved within the Spring config, beans retrieved via BeanFactory calls may not resolve those.
See this previous SO topic for more info.