I'm new to spring, but not new to java.
I'd like to create base class for all REST services that would send notification through some messaging protocol on requests with chosen methods (POST, PUT, PACTCH) (when resource is changed basically)
So for example If I would create interface
public interface RestService<T, I> {
T get(I id);
T create();
T patch(I id);
T put(I id);
}
How can I use that in spring RestController and somehow decorate it with notifications?
All this spring #Autowire and configuration files is somewhat confusing to me, because while I'm familiar with dependency injection and used constructor dependency injection I haven't used IOC much.
I believe that the best option for you will be to use Spring AOP and put some annotation to the required methods. Please check this:
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html
You can use any interface or base class for any restcontroller or for any other Spring stereotype. The annotations are just clues for Spring itself to use the class as an endpoint for a rest service for example. Your class otherwise can be anything, like:
#RestController
class MyController {
#Autowired
private MyService myService; //If you use the spring sterotypes you dont need to do anything to use a bean but just to use the autowired annotation
}
#RestController
class AnyotherController extends AbstractController {...}
#RestController
class YetAnotherController extends AbstractController implements Something {}
Are all valid resources (i.e. web-components) for Spring to use.
Related
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
I'm migrating code from JEE to SpringBoot. I was using cool dynamic injection in JEE with javax.enterprise.inject.Instance class:
Just annotating:
#Inject
private Instance<CCIntentHandler> allMycandidates;
Will make allMycandidates be filled with all classes inheriting CCIntentHandler interface in my classpath which then I can iterate simply with:
Iterator<CCIntentHandler> iterator = allMycandidates.iterator()
Nothing more needed. How can I achieve this in Spring Boot?
Thanks
Spring will inject all instances of Foo if you #Autowire a List<Foo>.
So, the Spring equivalent of ...
#Inject
private Instance<CCIntentHandler> allMycandidates;
... is:
#Autowire
private List<CCIntentHandler> allMycandidates;
Update 1 in response to this comment:
Do CCIntentHandler interface or classes implementing this interface need any Spring annotations?
Spring must be aware of any instances of CCIntentHandler, this could achieved as follows:
Annotate each class implementing CCIntentHandler with #Component and ensure that these classes are scanned by Spring Boot
Or
Provide a public method to return each class implementing CCIntentHandler and annotate each of these public methods with #Bean and ensure that the class which contains these public methods is annotated with #Configuration and that this configuration class is scanned by Spring Boot.
More details on bean declaration and dependency injection in the docs.
Unfortunately
#Autowire
private List<CCIntentHandler> allMycandidates;
is not
#Inject
private Instance<CCIntentHandler> allMycandidates;
because we can't select an instance from the list depending on type or annotation.
I've spent some time to find alternative in Spring, but looks like there is no equivalent...
We should defenetly bring that feature to Spring!
In Spring DI, we can bind an interface with an instance programmatically as below:
#Bean
public MyService getMyService() {
return new MyService1();
}
Is there a way to bind the interface with MyService1.class instead? I do not want to create the instance myself.
You can annotate your MyService1 class with #Service (or #Component, #Repository and others...).
This way, when you inject a MyService interface, it will automatically look for existing implementations and find MyService1.
Note that your Spring configuration must contain component scanning or equivalent.
NB : if you have multiple implementations of your interface, you can use #Qualifiers.
I have a Spring AOP aspect used for logging, where a method can be included for logging by adding an annotation to it, like this:
#AspectLogging("do something")
public void doSomething() {
...
}
I've been using this on Spring beans and it's been working just fine. Now, I wanted to use it on a REST-service, but I ran into some problems. So, I have:
#Path("/path")
#Service
public class MyRestService {
#Inject
private Something something;
#GET
#AspectLogging("get some stuff")
public Response getSomeStuff() {
...
}
}
and this setup works just fine. The Rest-service that I'm trying to add the logging to now has an interface, and somehow that messes stuff up. As soon as I add the #AspectLogging annotation to one of the methods, no dependencies are injected in the bean, and also, the aspect is newer called!
I've tried adding an interface to the REST-service that works, and it gets the same error.
How can having an interface lead to this type of problems? The aspect-logger works on classes with interfaces elsewhere, seems it's only a problem when it's a REST-service..
Ref the below Spring documentation (para 2) -
To enable AspectJ annotation support in the Spring IoC container, you
only have to define an empty XML element aop:aspectj-autoproxy in your
bean configuration file. Then, Spring will automatically create
proxies for any of your beans that are matched by your AspectJ
aspects.
For cases in which interfaces are not available or not used in an
application’s design, it’s possible to create proxies by relying on
CGLIB. To enable CGLIB, you need to set the attribute
proxy-targetclass= true in aop:aspectj-autoproxy.
In case your class implements an interface, a JDK dynamic proxy will be used. However if your class does not implement any interfaces then a CGLIB proxy will be created. You can achieve this #EnableAspectJAutoProxy. Here is the sample
#Configuration
#EnableAspectJAutoProxy
public class AppConfig {
#Bean
public LoggingAspect logingAspect(){
return new LoggingAspect();
}
}
#Component
#Aspect
public class LoggingAspect {
...
...
}
In my opinion what you are actually trying to do is to add spring annotations to a class maintained by jersey. In the result you are receiving a proxy of proxy of proxy of somethng. I do not think so this is a good idea and this will work without any problems. I had a similar issue when I tried to implement bean based validation. For some reasons when there were #PahtParam and #Valid annotations in the same place validation annotations were not visible. My advice is to move your logging to a #Service layer instead of #Controller.
there is on interface and no implementation.
Interface Test{
#MyAnnotation
pubilc void sayHello();
}
and i want to using spring to proxy that and let it can be autowired in other beans ,like
Class App{
#Autowired
Test test;
}
and in some proxy class i will handle invoke of 'sayHello' by some custom actions according to its annotation .
so how to config the spring xml file and how to write some "MethodInvokeHandler" class ?
i want to add some configuration to spring xml and assign "base-package" to scan these interface and generate the auto proxy code into spring context , so i can use #autowired to inject them to other bean .
This function is no standard spring functionality, so you can not configurate, you have to implement it.
But Java supports you with the Dynamic Proxy API, and its core class Proxy.