Engineering Full Stack Apps with Java and JavaScript
Implement factory pattern in Spring when using Java configuration.
Factory design patterns help you create objects without using the new keyword directly within your code. The factory intern will create object for you. You can read more about factory pattern @ Factory Design Patterns.
We will newly create a factory class with a method that accept a String and return the object of a class. We will create a bean for factory within the java configuration file, which will be injected to other bean methods and using this bean we will be creating other beans. In the example, I have used a maven pom file with dependencies for spring-context and have specified the compiler level as Java 8. You may even use Spring Boot to do the same example.
Package: com.javajee.spring.service
JJWriter.java
package com.javajee.spring.service;
public interface JJWriter {
public void write();
}
JJFileWriter.java
package com.javajee.spring.service;
public class JJFileWriter implements JJWriter {
public void write() {
System.out.println("Writing to File!!!");
}
@Override
public String toString(){
return "Writing to File!!!";
}}
JJDatabaseWriter.java
package com.javajee.spring.service;
public class JJDatabaseWriter implements JJWriter {
public void write() {
System.out.println("Writing to Database!!!");
}
@Override
public String toString(){
return "Writing to Database!!!";
}
}
WriterFactory.java
package com.javajee.spring.service;
public class WriterFactory {
public JJWriter getWriter(String str) {
switch (str) {
case "file":
return new JJFileWriter();
case "db":
return new JJDatabaseWriter();
default:
return null;
}
}}
Package: com.javajee.spring.controller
WriterController.java
package com.javajee.spring.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;import com.javajee.spring.service.JJWriter;
@Controller
public class WriterController {@Autowired
JJWriter writer;
public void write(){
writer.write();
}}
Package: com.javajee.spring.config
DemoConfig.java
package com.javajee.spring.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.context.annotation.PropertySource;import com.javajee.spring.service.JJWriter;
import com.javajee.spring.service.WriterFactory;@Configuration
@ComponentScan(basePackages="com.javajee.spring")
@PropertySource("classpath:/application.properties")
public class DemoConfig {
@Bean
public WriterFactory getWriterFactory(){
return new WriterFactory();
}
@Bean
@Profile("fileprofile")
public JJWriter getJJFIleWriter(WriterFactory factory)
{
return factory.getWriter("file");
}
@Bean
@Profile({"default","dbprofile"})
public JJWriter getJJDatabaseWriter(WriterFactory factory)
{
return factory.getWriter("db");
}}
Package: com.javajee.spring
Main class: JJWriterMain.java
package com.javajee.spring;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;import com.javajee.spring.config.DemoConfig;
import com.javajee.spring.controller.WriterController;
import com.javajee.spring.service.JJWriter;public class JJWriterMain {
@Autowired
JJWriter writer;public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(DemoConfig.class);WriterController writerController = context.getBean("writerController", WriterController.class);
writerController.write();
context.close();}
}
In this example, I have used annotations and Java configuration. However, factory implementation makes more sense in xml configuration due to some useful tag support provided by Spring xml configuration.
This example also makes use of many other annotations and concepts we have learned in this section like controller, componentscan, configuration, bean, profile, autowired etc. We will refactor the code into different packages and show the use of annotations like @Controller. Note that, technically you can use @Component or any other layer based annotations here. You can use @ComponentScan for all of these annotations. I have used the same application.properties file with a single line for activating the profile: spring.profiles.active=dbprofile. I have specified the file through @PropertySource annotation over my java configuration file.