I am learning Spring and I have a question regarding how you use it in standalone applications (and also when using it for making web applications). The examples I have been coded so far has used a simple main method where I retrieve beans by calling getBean on the. Context object. However, you probably want to do this in multiple classes so do you first get a context and then call getBean or are there other cleaner alternatives? Or is this the way you do it in standalone and web apps?
If you're calling context.getBean() everywhere, you're probably missing the whole point of Spring, which is a dependency injection framework.
In a standalone app, you typically call context.getBean() only once (or at least, very rarely), in order to get a "root" bean. This bean is injected by Spring with other beans, and so on.
In a web app, it all depends on which framework you use. But typically, you register a listener in the web.xml which loads the context for you, and controllers are created and/or injected by Spring.
You're on the right lines. Your main method will initialise your application context as you've discovered. The trick then is to use that app context to create the entry point to your application. That bean, having been created with spring will have been wired for you..
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ApplicationMain {
public static void main(String[] args) {
AbstractApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:/META-INF/spring/applicationContext.xml");
MyApplication app = BeanFactoryUtils.beanOfType(ctx, MyApplication.class);
app.init();
}
}
One class (your main class, probably) has to be Spring-aware to create the context. All other classes can continue to be wired together via Spring and do not need to be Context-aware.
It kind of depends on the application you are writing, but you should limit getBean() invocations to minimum, preferably one. You are fetching the first bean directly from the context and put the rest of the logic in the beans themselves. Something along the lines:
Bootstrap boot = context.getBean(Bootstrap.class);
boot.start();
And all the rest of your application logic is taking place within start(). It can create threads, listen for events, etc.
Related
Env:
Wildfly 8.2.0 Final
JDK 8
Java EE 7
Please note that by 'POJO' i am referring to the classes that serve the other classes i.e other than value objects, entities.
This question was on back of my head for some time. Just wanted to put it out.
Based on CDI and Managed Beans specs and various other books/articles, its pretty clear that CDI injection starts with a 'managed' bean instance. By 'managed' i mean servlet, EJBs etc. which are managed by a container. From there, it injects POJOs (kind of crawl through layers) till every bean gets its dependencies. This all makes very sense to me and i see very little reason why developers ever need to use "new" to create an instance of their dependent POJO's.
One scenario that comes to my mind is when developer would like to have logic similar to
if(something) {
use-heavy-weight-A-instance
} else {
use-heavy-weight-B-instance
}
But, that also can be achieved via #Produces.
Here is one scenario that i verified to be true in wildfly 8.2.0 Final i.e. CDI is not able to inject bean when the JSP has
<%!
#Inject
BeanIntf bean;
%>
But, the alternative to use a servlet works fine.
That said, would like to know if there is any scenario(s) where a developer has to use 'new'. As i understand, by using 'new', developer owns the responsibility of fulfilling dependencies into that bean and all its dependent beans, and their dependent beans etc..
Thanks in advance,
Rakesh
When using CDI or other container you don't use new, because you expect a bunch of service coming from the container.
For CDI these main services are:
Injection of dependent beans (get existing instance or create a new
instance)
Lifecycle callback management (#PostConstruct and
#PreDestroy)
Lifecycle management of your instance (a #RequestScoped bean will make container produce an instance leaving until the end of request)
Applying interceptors and decorators on your instance
Registering and managing observers methods
Registering and managing producers methods
Now, on some rare occasion, you may want to add a part of these services to a class you instantiate yourself (or that another framework like JPA instantiate for you).
BeanManager bm = CDI.current().getBeanManager();
AnnotatedType<MyClass> type = bm.createAnnotatedType(MyClass.class);
InjectionTarget<MyClass> it = bm.getInjectionTargetFactory(type).createInjectionTarget(null);
CreationalContext<MyClass> ctx = bm.createCreationalContext(null);
MyClass pojo = new MyClass();
injectionTarget.inject(instance, ctx); // will try to satisfied injection points
injectionTarget.postConstruct(instance); // will call #PostConstruct
With this code you can instantiate your own MyClass containing injection points (#Inject) and lifecycle callbacks (#PostConstruct) and having these two services honored by the container.
This feature is used by 3rd party frameworks needing a basic integration with CDI.
The Unmanaged class handle this for you, but still prevent you to do the instantiation ;).
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 am developing an non-web application and I would like to set up Spring in it. I would like to have minimal configuration that supports auto-wiring. What's the proper way to do this? Do I need to implement my own ApplicationContext loading mechanism, or is there something better I could do?
Spring provides an IoC container in the form of an ApplicationContext. However, you need to implement your own mechanism for creating the container. But that can be pretty simple
public class Start {
public static void main(String[] args) {
ApplicationContext context = ...// whichever flavor you want
// maybe start some threads, possibly managed by the IoC container
}
}
The container itself can either use XML configuration or a programatic one. Read the official documentation on how to do either, here.
Imagine we have a java package. This package can be used anywhere. However, there are some codes in this package which are context dependant. For instance, if the application which uses this package is a web app we need to perform some tasks by calling a function while performing other tasks if the application was a console application by calling the very same function.
Here is my question:
Is there any way in java that within the code we can detect if the application was run as a web app or a console?
I appreciate any help :)
As a real world example, the ways we load properties files are different for web and console applications.
For web applications we probably use this.getClass().getClassLoader().getResourceAsStream(url) and for console apps we use new FileInputStream(physical path).
It might be better to set a build property somewhere rather then trying to detect your application type, because I don't think there is a reliable way to do that.
Moreover you shouldn't try to detect application type because your view layer (either web, desktop or console) should be easily interchangeable according to modern architectural principles.
In response to your last comment.
As user384706 said DI is the correct choice here IMO.
I will give an example with spring.
In both your console and web app parts you can have:
public class WebOrConsoleServiceImpl {
private PropertyProvider propertyProvider = new NullPropertyProvider();
// and
public void setPropertyProvider(PropertyProvider impl) {
this.propertyProvider = impl;
}
// and in your service logic
public void logic() {
final Properties props = propertyProvider.loadProperties();
// do stuff
}
}
Where your loadProperties() method would be overriden for different implementations of your PropertyProvider.
And in your spring context you can have:
<bean id="consolePropertyProvider" class="com.company.ConsolePropertyProvider"/>
<bean id="myConsoleService" class="com.company.MyConsoleService">
<property name="propertyProvider" ref="consolePropertyProvider" />
</bean>
And the same pair of bean definitions for your WebService and WebPropertyProvider.
Just use dependency injection
Just place all the appropriate parameters to configure your library via setters and let the container or application configure it accordingly using DI.
So you will not need any checks which IMHO is a bad approach
The J2EE way. If your package is used in a web application then, I am assuming that you are in a J2EE container then, you can add a Reference in the naming at deploy time. You can also register an MDB that can listen to the changes to this reference and modify behavior of your code at runtime. Sweet right?
Other standard way in which you can pass the context of the caller is through a parametrized Factory or through properties.
One non-standard way - for fun is to get the stack trace and look for who the caller is or look for j2ee context etc.
I have an elaborate Spring bean setup for integration tests. Now I'm looking into writing a Robot library to expose my test data creation / behavior execution / assertion methods to Robot tests.
However what I understand from the Robot Framework user guide is that Robot can only instantiate library classes by calling a constructor. This is a bummer because I'd rather have my instances managed by Spring.
Ideally, I'd want to be able to give Robot the path to the application context and the bean name for the library. Failing that, I'd want Robot to be able to invoke a static factory method rather than a constructor, so I'm not forced to create a new instance.
One workaround I thought of is to create the Spring context in a static initializer and wire my dependencies by fetching beans from that context.
My original class looks like:
public class MyAwesomeTests {
#Autowired
private ThisHelper thisHelper;
#Autowired
private ThatHelper thatHelper;
// implementations of test steps and such
}
So I would change the above #Autowired fields to be protected, and create a subclass that statically initializes the Spring context and defines a Robot-friendly constructor:
public class RobotFriendlyTests extends MyAwesomeTests {
private static final ApplicationContext CONTEXT = new ClassPathXmlApplicationContext(...);
public RobotFriendlyTests() {
this.thisHelper = (ThisHelper) CONTEXT.getBean("thisHelper");
this.thatHelper = (ThatHelper) CONTEXT.getBean("thatHelper");
}
}
This should work, but it feels somewhat clunky. Is there a better way I should consider? Better yet, is there a Robot extension that already does this for me?
Have you thought about using Spring #Configurable, then even instances created by a normal new will become spring managed beans.
#See Spring Reference Chapter 7.8.1 Using AspectJ to dependency inject domain objects with Spring
There's a Robot Framework extension that supports using Spring to wire test libraries, take a look at: http://code.google.com/p/robotframework-javalibcore/wiki/SpringLibrary
I am not entirely sure whether it supports your case since I am not familiar at all with Spring.