I have combination of web and core projects under the same maven parent module as like,
Parent
- Web (com.parent.test.web)
- Core (com.parent.test.core)
I would like to refer the web module dependency in the core project to invoke some of the api from web module
Web project sample,
com.test.parent.web
public interface RestInterface {
public ResponseEntity load();
}
#RestController
public class RestInterfaceImpl implements RestInterface {
#Override
#RequestMapping(value = "/getData", method = RequestMethod.GET, produces = APPLICATION_JSON)
public #ResponseBody ResponseEntity<Object> load() {
}
}
Core project sample,
com.test.parent.core
#Component
public class CoreImpl implements CoreInterface {
// Is this possible to autowire
#Autowired
private RestInterface restInterface;
public boolean getOptions() {
ResponseEntity<Object> results = restInterface.load();
for (Object o : results) {
//TODO
}
}
}
Because the projects are developed within the same parent pom module. All the projects will be grouped into a springboot jar and will be deployed into the same environment. So, I'd like to refer the web project dependency into the core project and trying to scan the web classes inside the core project.
I'd like to get clarified on few things ,
Is it the good approach ?
If it is the good approach, how we can implement ?
If not then what will be correct approach ?
IMHO it is definitely not a correct approach. The separation of concerns principle says that controllers should only be small pieces of code that take parameters from the requests, pass them to business classes, and forward to a view that will display the results.
If you need to call some methods of the controller from a core class, it means but you have a Fat Ugly Controller carrying business methods inside it. The correct approach is to separate the web part => controller, from the business part => service layer.
That way you create a service bean that will be autowired in both the (now thin) controller and the other core classes that need to call its methods.
Related
With spring boot 2.6.0 (or above) is it possible to generate a rest client from a a controller interface?
Im wondering if its possible to build spring application like this following use case.
Spring application A needs to call spring application B rest interface
Spring application B is a multimodule project that produces server jar, and a api jar
Spring application A imports the B's API jar
Spring application A uses controller interface from B Api jar to make a rest client based on spring annotations.
B Api jar:
#RestsController
public interface MyApplicationAPI {
#GetMapping("/api/some-endpoint)
public SomeDto someEndpoint(SomeDTO obj);
}
B server jar:
public class BApplicationAPIImpl implements MyApplicationAPI {
public SomeDto someEndpoint(SomeDTO obj) {
return xxx;
And finally within A application:
MyApplicationAPI restClient = Some.magic(MyApplicationAPI.class, "http://bappurl.com")
SomeDto response = restClient.someEndpoint(param);
I believe that framework RestEasy supports similar approach, but you have to rely on JAXRS annotations.
Is there anything like that for spring framework? Or even better is there anything like this within spring already - i would prefer to rely on spring inhouse libraries and tools, rather than importing entire resteasy and jaxrs.
Spring Framework 6 (and Spring Boot 3) will have declarative HTTP interfaces (see documentation). However, they won't use the same annotations as controllers, but separate ones. So your example where you use the same interface for both controller and client won't be possible.
Code snippet from the documentation:
interface RepositoryService {
#GetExchange("/repos/{owner}/{repo}")
Repository getRepository(#PathVariable String owner, #PathVariable String repo);
// more HTTP exchange methods...
}
Initialization (the Some.magic() part in your question) can be done with WebClient. As can be seen in the same documentation:
WebClient client = WebClient.builder().baseUrl("https://api.github.com/").build();
HttpServiceProxyFactory factory = WebClientAdapter.createHttpServiceProxyFactory(client);
factory.afterPropertiesSet();
RepositoryService service = factory.createClient(RepositoryService.class);
I am writing a small CRUD in Spring and Java. And I want to use a separate file for writing logic, this is very convenient for me, I did this when developing with NestJS. I have a few questions, is it correct to do this in Spring, or should I do everything inside a function in the controller. And if I write logic in a separate file, I should mark the logic class as #Component and the functions inside it as #Bean, right? I am new to Spring and as I understand it, I have to do this in order for the application to work correctly and my functions to be in the application context.
AuthLogic.java
#Component
public class AuthLogic {
#Bean
public void register() {
// code ...
}
}
AuthController.java
#RestController
public class AuthController {
#RequestMapping(value = "/register", method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
public void register(#Valid #RequestBody UserDTO newUser) {
// here I call the register function from AuthLogic
}
}
you can mark your logic class with #Service and use that for example you can make a AuthService and use it like
#Service
public class AuthService{
public returnType login(){
//Logic
}
}
and use this like
#RestController
public class AuthController {
AuthService authService;
#RequestMapping(value = "/register", method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
public void register(#Valid #RequestBody UserDTO newUser) {
authService.login();
}
}
You can write your business logic in a new separate file at service layer.
Suppose you name it as AuthService and you mark it with annotation #Service.
#Service
public class AuthService{
}
You can then Autowire it in your controller class.
#RestController
public class AuthController {
#Autowired
AuthService authService;
#RequestMapping(value = "/register", method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
public void register(#Valid #RequestBody UserDTO newUser) {
// here I call the register function from AuthLogic
}
}
Using separate files, or classes more importantly, is very recommended in Spring, and I assume most other languages.
The #Bean annotation on AuthLogic.java is unneeded and I think may cause startup or compilation errors.
I would change the name of AuthLogic to AuthLogicImpl, create an interface named AuthLogic with the method signature void register(), and have AuthLogicImpl implement AuthLogic. Then you can create a constructor for AuthController which accepts and AuthLogic parameter and sets it to a private field (note using the interface not the implementation in the constructor).
At the core of Spring is the IoC container. This container holds "beans" that can be injected or autowired into other beans. These beans are an instance of their class and can be used by other beans. Remember Spring uses the singleton pattern, so your beans should be stateless. This allows Spring to handle the application startup for you, so you don't need to write a ton of code creating all the different services/classes and wiring them together, it's all automagically done for you.
There are two key annoitations that you appear to be confused about:
#Component Putting this above a class will create an instance of that class (a bean) and put it into the IoC container. Other beans can access this by accepting the original beans interface in its constructor. So if I put #Component above my class FooImpl which implements Foo, then I can create a class, BarImpl with the constructor public BarImpl(Foo foo) {this.foo = foo} and BarImpl can use any public method of Foo (which will use FooImpl's implementation).
#Bean this is to be put on a method of a class that is annotated with #Configuration. This tells Spring that this method should be run at startup, and this method will return a bean that Spring should add to the IoC container. This is a popular way of configuring a bean that requires some parameters, such as the bean that manages the connection to a third party service or datastore, especially when that there is a little bit of logic that needs to go into creating the bean.
Note that the above is very broad, and there are some specifics if you need to dig deep into the spring framework, so there will be more clarification in the Spring documentation or you dig into some established Spring project. However it should suffice to answer the broad question of what is going on with #Component and #Bean.
There is no specific layout or code structure for Spring Boot Projects. However, there are some best practices followed by developers that will help us too. You can divide your project into layers like service layer, entity layer, and repository layer.
We use the entity layer to write all model and POJO classes. We annotate them with #Entity.
We use #Repository to indicate that this is a repository interface that is used to do some basic CRUD operations.
Sidenote:- You don't have to write #Repository for classes that implement or interfaces that extends Repository interfaces provided by Spring Boot framework.
We use #Service to say that this is the service class where your all business logic will be present.
We use the controller layer to receive HTTP requests and send back HTTP Responses or views.
You can learn and understand more from here
You can refer to this Image to understand the structure
project structure
Importing custom spring-boot library jar to my application, and autowiring show the following error when I run the application
Parameter 0 of constructor in com.dilla.de.orca.addresssvc.service.TestScheduler required a bean of type 'com.dilla.de.orca.flowersvc.service.FlowerServiceImpl' that could not be found.
The Library module has following packages
Configuration
FlowerServiceConfiguration - create beans for Jaxb2Marshaller, WebServiceTemplate,
webserviceMessageSender
Model
Service
FlowerService (an interface no annotation)
FlowerServiceImp implements the interface and calls FlowerAdapter
FlowerAdapter (call external webservice)
Src/main/resources
Application.properties define external webservice url, and related properties
FlowerSvcLibApplication.java
public static void main(final String[] args) {
SpringApplication.run(FlowerSvcLibApplication.class, args);
}
I was autowiring the Flower Service interface as follows, in my application to test functionality
of library jar
#Component
public class MyFlowerService {
private FlowerService service;
#Autowired
public MyFlowerService(final FlowerService service) {
this.service = service;
}
I got the error I posted earlier. I did do more research, and one suggestion was creating “own auto-configuration”, but I still did not understand. How do I create autoConfiguration class to handle to autowire my library class, and also how does client using my library provide application property values. Currently, I hard coded actual values for example a webservice url, and now client can change this to be test or prod, and to do that how does my library module setup should be?
Please check #ComponenetScan & make sure that it has package path something like this “com.dilla.de.orca”
EurekaServer: register/expose services
EurekaClients: provide services
FeignClients: consume services and provide APIs
I'm using Feign for service consumption. I wonder if feign interfaces (interfaces that annotated with #FeignClient) should be put in EurekaClients or FeignClients?
If Feign interfaces are put in EurekaClients.
GOOD: I only need to write only one copy of Feign interfaces, and implement it in the EurekaClients. For any FeignClients that need to use this service, import these interfaces from EurekaClients and just use it.
BAD: Module dependencies could be easily set, but it is hard to do mvn package or using docker for production. As the problem I stated HERE.
If Feign interfaces are put in FeignClients(almost every examples I can find on the internet do like this).
GOOD: Easy to build.
BAD: A lot of duplicated code. Because for every FeignClient I need to re-write #FeignClient annotated interfaces. If there are a lot of nested FeighClients and EurekaClients, it would be too difficult to maintain.
So any suggestions for a good practice of Where should I put Feigh interfaces ?
Here is the pattern we followed in our projects. Each service has two projects, e.g., :
Service A
model
service
All the controllers and other business related classes, e.g, DAOs, service, Repository classes are kept in the service project. While the models used by the controller and exposed to the outside world are kept in the model project. The controller also implements an interface which exposes the REST API. This interface is kept in the model project also.
public interface AuthorService {
#RequestMapping(method = RequestMethod.GET, produces = {
MediaType.APPLICATION_JSON_VALUE}, value = "/authors/{id}")
#ResponseBody
Author getAuthor(#PathVariable("id") Integer id);
}
The AuthorService interface and the model, Author are kept in the model project. The controller, AuthorController which implements the AuthorService is kept in the_service_ project.
Let's say ServiceB uses ServiceA, then the former import's the latter's model project. In ServiceA's service, we create a Feign interface, e.g.,
#FeignClient(name = "author", fallback =
AuthorServiceFallbackClient.class)
public interface AuthorServiceClient extends AuthorService {
}
This pattern helped us to reduce quite a bit of code duplication.
I have a requirement of compatibility with a new architecture based in Spring 3.2. The requirement is: a http request will come to a controller with an attribute that defines which kind of object is required. For example ...mycontroller/load?objType='obj1'.
My controller will have this structure:
#Controller
public class myController{
private ObjectService objectService;
#Autowired
public setObjectService(ObjectService objectService){
this.objectService = objectService;
}
}
So after that, I need to check this attribute to decide which service will I use. For example, this case is Obj1Service (method: "load"). All this services are extended from ObjectService, so: It is a good idea to swap objectService dependency to Obj1Service / Obj2Service in each incoming call? For example:
if(objType.equals("obj1")) this.setObjectService(context.getBean("obj1Service"..))
if(objType.equals("obj2")) this.setObjectService(context.getBean("obj2Service"..))
I know that is not a great design, but we need to integrate this new modules with other system that produces this kind of http requests.
It is necessary the inheritance because we have very similar behavior in many service's code, but with modifications in internal methods, so part of the behavior will be placed in ObjectService (it is not abstract) and other portion of the code will be placed in it children. Is there another way, more appropriate, to do this? Or you consider that is an acceptable solution?
Thanks!
You can use a map for all of your services, and get the appropriate service inside each controller method.
Let's say you have two services:
#Service("obj1")
public class ObjectServiceImpl1 implements ObjectService {
...
}
#Service("obj2")
public class ObjectServiceImpl2 implements ObjectService {
...
}
In your controller:
private Map<String, ObjectService> objectServices;
#Autowired
public setObjectServices(Map<String, ObjectService> objectServices){
this.objectServices= objectServices;
}
Spring will inject the map with all the ObjectService beans mapped by their names.
In load?objType=obj1 handler, you would have something like:
objectServices.get("obj1").doSomething(); // will use ObjectServiceImpl1
The same with load?objType=obj2 handler:
objectServices.get("obj2").doSomething(); // will use ObjectServiceImpl2
And so on.