Bare metal setup for Spring DI - java

Say I just want to have a simple Java executable (executable JAR) use Spring XML for dependency injection. I don't want any other Spring JARs or functionality (i.e. Spring MVC, Spring Batch, etc.). I simply want to use Spring for dependency injection and nothing more.
What are the bare bones minimal JARs I need on the classpath, and implementation I need to set up in my main Driver class (see below) to read a myapp-config.xml off the runtime classpath and inject the "roots" of my dependency tree?
public class Driver {
private Widget widget;
public static void main(String[] args) {
Driver driver = new Driver();
driver.start();
}
public void start() {
// By this point, the widget instance should have been injected by Spring.
widget.doSomething();
}
// Getter & setter for widget.
}

Related

Apache Camel File-Watch Without Spring

I am trying to use Apache Camel File-Watch feature.
However I notice all example are used along with Spring.
Is there anyway to make use of this feature without Spring ?
Thank you for any potential input.
Best regards.
Apache Camel is a standalone integration framework to easily integrate different systems using well know and established EIP (Enterprise Integration Patterns).
It is not tied to Spring in any way at its core and has different deployment / integration models out of which is Spring / Spring Boot for the sake of easing its adoption and configuration for Spring framework users.
Out of the runtime contexts, you can use for example Camel Main component to run your application having a File Watch component setup to watch the /tmp/ directory change events:
The main application would look like the following:
public class FileWatchApplication {
private FileWatchApplication() {
}
public static void main(String[] args) throws Exception {
// use Camels Main class
Main main = new Main(FileWatchApplication.class);
// now keep the application running until the JVM is terminated (ctrl + c or sigterm)
main.run(args);
}
}
A simple RouteBuilder setting up your File Watch component would look like the following (note that it must be within the same (or child) package of the FileWatchApplication class):
public class FileWatchRouteBuilder extends RouteBuilder {
#Override
public void configure() throws Exception {
// snippet configuration from the official documentation
from("file-watch:///tmp/")
.log("File event: ${header.CamelFileEventType} occurred on file ${header.CamelFileName} at ${header.CamelFileLastModified}");
}
}
Camel is based on Spring. In fact, the Camel Context is an extension of the Spring Application Context. So if you have Camel, you also must have Spring.

How does class gets injected which implements interface method being called in Java or Groovy code?

I have below working groovy code from Spring framework project:
import org.springframework.oxm.Unmarshaller
public class ItemSearchService {
Unmarshaller unmarshaller;
public ItemSearchResponse getObject(InputStream xml) {
ItemSearchResponse its = null;
try {
its = (ItemSearchResponse) unmarshaller.unmarshal(new StreamSource(xml));
} finally {
}
return its;
}
}
Unmarshaller.unmarshall is actually interface method:
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/oxm/Unmarshaller.html
Unmarshaller interface is implemented by several classes.
Who decides which implementing class to inject during runtime and how it decides which class to use?
Does Spring IoC mechanism does this? If so does it pick up one specific implementing class during build time when jar is generated or it does it during run time?
Also how to know which implementing class it actually used?
Will above code work outside of Spring in ordinary Java file assuming dependent jars in classpath?
As soon as it goes about a Grails project (not a pure Spring one), some things should be clarified.
Who decides which implementing class to inject during runtime and how it decides which class to use? Does Spring IoC mechanism does this? If so does it pick up one specific implementing class during build time when jar is generated or it does it during run time?
What Spring does in a plain Spring(Boot) is nicely described by #svr s answer and other documentation on the Internet, but has not much to do with your case.
In Grails the convention-over-configuration doctrine is used, meaning that
by default Bean Autowiring is active
only beans which are declared as Grails artefacts, like Service are auto-injected.
Usually, if you want to autowire a bean of other stereotype, you have to declare it somewhere, otherwise Spring IoC container inside Grails simply won't find it.
You shall check your grails-app/conf/spring folder for resources.groovy (or maybe yaml or xml files depending on version ) and see if your unmarshaller bean is defined there. It should look like:
beans = {
unmarshaller Unmarshaller ....
}
So, basically it doesn't matter how many implementations of Unmarshaller interface are present in all project's jar files. The only thing what matters is what defined in your resources.groovy.
If you want to check the class of the bean in runtime, just log it's class in your service:
class ItemSearchService {
Unmarshaller unmarshaller
ItemSearchResponse getObject(InputStream xml) {
log.info "unmarshaller's class is $unmarshaller.class"
// or
// println "unmarshaller's class is $unmarshaller.class"
}
}
Who decides which implementing class to inject during runtime and how
it decides which class to use?
Does Spring IoC mechanism does this? If so does it pick up one
specific implementing class during build time when jar is generated or
it does it during run time?
Yes Spring IOC container. It happens at run time when the application is run.
Also how to know which implementing class it actually used?
For most part you will have to define bean with implementation to pick. For other cases you can look at the spring auto configuration classes.
Will above code work outside of Spring in ordinary Java file assuming
dependent jars in classpath?
Not sure what you mean outside of Spring but as long as application is packaged correctly it should all work.
Quick Overview
Spring IOC will only inject a bean when found in the application context. An application context loosely is repository of beans.
Classpath Scanning and Registration
Spring scans application to pick up all the stereotyped classes and registers bean definition with application context. Stereotyped annotations include #Component, #Repository, #Service, #Controller, #Configuration. More
Dependency Injection
Spring DI creates the bean and injects them as dependencies into application. You can create dependencies between different application components using the registered beans and spring will autowire these for you. More. There are two types of DI - Constructor based and setter based - Constructor for required dependencies and setter based for optional dependencies. More
There are sensible defaults provided when you use any spring classes. You just have to define the bean where there is no default or you would like to pick different implementation. Application context can be further be enriched by using Spring Boot Auto Configuration where all related classes are wired together to form a coherent entry classes. You can then easily inject these into application for getting started. More
Example
You can define bean in the #Configuration class for a web service module.
#Configuration
public class WSConfig {
#Bean
public Jaxb2Marshaller marshaller() {
Jaxb2Marshaller marsharller = new Jaxb2Marshaller();
marsharller.setContextPath("some package");
}
#Bean
public WebServiceTemplate webServiceTemplate(Jaxb2Marshaller marsharller) {
WebServiceTemplate webServiceTemplate = new WebServiceTemplate(marsharller);
}
}
#RequiredArgsConstructur
public class ItemSearchService {
private final Unmarshaller unmarshaller;
public ItemSearchResponse getObject(InputStream xml) {
ItemSearchResponse its = null;
try {
its = (ItemSearchResponse) unmarshaller.unmarshal(new StreamSource(xml));
} finally {}
return its;
}
}
This similar configuration is automatically taken care by WebServicesAutoConfiguration with ways to customize when using Spring Boot.

How to inject extra property sources in SPRING before other beans are created?

I am writing a library which will be used by spring-boot projects. I'd like to inject into the boot projects' SpringEnvironment a property source that I take from the Internet.
I tried the following
#Configuration
public class MyCustomConfiguration {
#Bean
BeanDefinedAbove above() { /* do some work */ }
#Bean
#ConditionalOnBean(BeanDefinedAbove.class)
SmartInitializingSingleton propertySourceSetting(ConfigurableEnvironment env, BeanDefinedAbove bean) {
return () -> {
PropertySource source = bean.getPropertySourceDownloadedFromTheInternet();
env.getPropertySources().addFirst(source);
}
}
}
In my clients' projects when I debug this code what happens is either one of the two:
above() is called
user's #Service or #Controller are called
propertySourceSetting(...) is called
OR
user's #Service or #Controller are called
above() is called
propertySourceSetting(...) is called
Depending whether or not my client's depend on my BeanDefinedAbove bean, which is normal as the #Service is depdent on the bean created in above().
I have also added the FQDN of my class to the EnableAutoConfiguration in the META-INF/spring.factories.
So how to ensure that the logic in propertySourceSetting(..) is called before users' #Service and #Controller
I'll provide you with three options.
Option 1: (THIS IS A BAD APPROACH, BUT A QUICK WORKAROUND)
Add #Lazy(false) annotation to both Beans. Spring will eagerly create those two beans, which they will probably be created before the other ones.
Why this is bad?
This does not ensure order. Spring decides the creation order based on dependencies and some other conditions. This is why it will "probably" work :)
Option 2: Create a main class to bootstrap Spring Boot Initialization (the old way of starting spring boot).
public static void main(String[] args) throws Exception {
SpringApplication application = new SpringApplication(MyApplication.class);
// ... add property source here before start
application.run(args)
}
You also need to specify main class in the manifest for Spring Boot like this: https://www.baeldung.com/spring-boot-main-class
In that main-class you would add your propertysource, kinda like this:
SomeClassThatRetrievesProperties propRetriever = new SomeClassThatRetrievesProperties ();
Map<String,String> properties = propRetriever.getAllPropertiesAsMap();
application.setDefaultProperties(properties);
Option 3: Create a CustomApplicationContext by extending WebApplicationContext and overriding getSpecificConfigurations() method.
This way you will have full control but we aware that you could break some important stuff.

Depending on a Spring project from a non-Spring project

I've got two Java applications that I have to combine. One is Spring, and methods within it need to be called by the second, an Elasticsearch plugin (that I don't think can be turned into a Spring app as it already uses some form of Guice for dependency injection).
The Spring class I need to call looks like:
#Component
public class DataServiceController {
//This is defined within a #Config
#Autowired
DataTypesMap dataTypesMap;
/**
* Create an item in the data platform
*/
public ItemCreatedResponse createItem(String data, String dataType)
throws IOException {
ProcessStrategy dataStrategy = dataTypesMap.get(dataType);
return dataStrategy.add(data);
}
If I just add this project as a Maven dependency within the ES plugin, the Autowired dataTypesMap is always null (which is to be expected as nothing in the Elasticsearch plugin will be telling it how to autowire).
What can I do here?
You can use a setter method for your autowired fields, then sets the value.
#autowired
public void setDataTypesMap (DataTypesMap dataTypesMap ){
this.dataTypesMap = dataTypesMap ;
}
In your application you can not autowired the bean, but you can set it.
myBean.setDataTypeMap();
The second option is initiate a the context of the spring application inside the non-spring application.
You can see how to do it here.
http://www.springbyexample.org/examples/intro-to-ioc-creating-a-spring-application.html

jdbi, guice with dropwizard

Hello I am trying to create an application using dropwizard framework. I have the DAO classes impl which needs an handle to connection manager instance which will then be used to get database connections. I have a multi tenant database application. This connection manager would be a custom implementation.
The application uses hikari cp as connection pool and mysql database. I want to initialize the datasource and connection pool using dropwizard managed object feature. Once the datasource is initialized I want to inject the connection manager instance in each of dao classes using guice binding something like
bind(ConnectionManager.class).toProvider(ConnectionManagerProvider.class);
Then in each dao impl classes
#Inject
public class UserDAOIpl extends AbstractDAO {
protected UserDAOImpl(ConnectionManager connectionManager) {
super(connectionManager);
}
}
I have looked everywhere on the net there is no particular example for my use case. Also there is a lack of documentation at dropwirzard.io
This is more of an architectural design question rather than code question.
The datasource module would be a separate module which would be used in many service. I am using maven as build tool.
My questions are
How I can approach this situation ? Some class names and implementation guide lines would be very useful.
The application would be handing half a million requests a day. The solution should be feasible.
I look forward to community for any guidance or if any body can point me to some good resources.
NOTE: We won't be using hibernate for this application and would be using JDBI.
I prepared a setup similar to the one you described as follows. It sets up guice, initializes a DBIFactory (you might need to adopt that part to your scenario). Then a JDBI object is handed over to a repository implementation that can use it to persist an entity of type Vessel.
(1) Adding guice to the project
<dependency>
<groupId>com.hubspot.dropwizard</groupId>
<artifactId>dropwizard-guice</artifactId>
<version>x.x.x</version>
</dependency>
(2) Setup Guice in initialize():
guiceBundle = GuiceBundle.<YourConfiguration>newBuilder()
.addModule(new GuiceModule())
.enableAutoConfig("your.package.name.heres")
.setConfigClass(YourConfiguration.class)
.build();
(3) Guice config for preparing JDBI elements
public class GuiceModule extends AbstractModule {
private DBI jdbi;
#Provides
public DBI prepareJdbi(Environment environment,
SightingConfiguration configuration) throws ClassNotFoundException {
// setup DB access including DAOs
// implementing a singleton pattern here but avoiding
// Guice to initialize DB connection too early
if (jdbi == null) {
final DBIFactory factory = new DBIFactory();
jdbi = factory.build(environment, configuration.getDataSourceFactory(), "h2");
}
return jdbi;
}
#Provides
public VesselJDBI prepareVesselJdbi(DBI jdbi) {
return jdbi.onDemand(VesselJDBI.class);
}
#Override
protected void configure() {
bind(VesselRepository.class).to(VesselRepositoryImpl.class);
/* ... */
}
}
(4) start using it in your classes
public class VesselRepositoryImpl implements VesselRepository {
private VesselJDBI jdbi;
#Inject
public VesselRepositoryImpl(VesselJDBI jdbi) {
this.jdbi = jdbi;
}
public Vessel create(Vessel instance) {
return jdbi.inTransaction((transactional, status) -> {
/* do several things with jdbi in a transactional way */
});
}
}
(please note: the last code example used Java 8. To use JDBI with Java 8 with Dropwizard 0.8.1 please use jdbi version 2.62 to avoid bug https://github.com/jdbi/jdbi/issues/144)
Please let me know if this helped you.
Best regards,
Alexander
I can't comment, but wanted to add on to Alex's answer:
For the repository implementation, I recommend having the repository be handled by jDBI instead of using Guice. Here's what I did:
In the Guice module, add a provide method:
#Provides
#Singleton
public void repository(Dbi dbi) {
// dbi.onDemand(whateverYourClassIs.class)
}
in the repository class, use #CreateSqlObject to have your DAOs available:
public abstract class Repo {
#CreateSqlObject
abstract Dao dao(); // will return a jDBI managed DAO impl
public void doWhatever() {
/// logic
}
}
This has the distinct advantage that you can now use jDBI annotations. (I have not found a way to use them with guice directly). This is very nice for example, if you need to execute DAO code in a transaction. The Repository is still handled within Guice so it can be injected anywhere, but jDBI handles the tricky bits within your DAO/Repository code.
Hope this helps :)
Artur

Categories