Load Applicationcontext on startup (non Web application) - java

I'm creating an application that use Spring Remoting.
I have my applicationContext.xml and i want to migrate it in a pure-code configuration.
Right not i have my main class with:
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
I would like to "centralize" the loading and #Inject my bean when needed, without using:
UsersRepository userRepositories = context.getBean(UsersRepository.class);
For WebApplication i've seen WebApplicationInitializer.
but what if the application is not Web Based (no web.xml ecc)

So, I cannot guarantee this is going to be entirely accurate, but here is how I do this.
In your service class (or whatever class is utilizing the UserRepository), you want to Make it an argument of the constructor and make it a global variable, add the #Inject tag above the constructor. Here is an example.
public class UserService {
private UserRepository userRepository;
#Inject
public UserService(UserRepository userRepository){
this.userRepository = userRepository
}
}
Like I said, this is how I do and we can access the repository freely from any of the methods in the class. Hope this helps.

Related

Is there any way to create a #ConditionalOnMissingBean but only after spring is fully configured?

I'm building a Spring Boot Starter for a college project on Java Reflection and Bytecode alteration.
The Reflection/Bytecode is done now, but it will scan for Spring #Controllers/#RestControllers so it can detect certain annotations to run the process.
My question here is what's the best approach? Seems to me that an annotation processor doesn't quite work nicely, and my idea is to create a #Configuration class. Now I need to ensure that all #Controller beans have been booted before I actually process them and I also need to put the result of this processing in a bean that could already exist.
So for example:
#Configuration
public class TestConfig {
#Autowired //I want to autowire but it may not exist, if the user doesn't define I need to create it
private ExternalAnnotatedRequestsModel model;
#Autowired // needed for the framework to acess spring controllers
private ConfigurableApplicationContext ctx;
#Bean // this can also be overriden since the definitions can be done via yaml
public ExternalRequestsProvider() {
return new AnnotationExternalRequestsProvider(ctx);
}
}
Now I also want that when the ExternalRequestsProvider bean is started, it runs the process method and saves the result in the object in the "model" variable.
Using #EventListener for ApplicationReadyEvent to run your process after Spring is fully configured.
#Configuration
public class ExternalRequestsConfig {
#Autowired
private ExternalAnnotatedRequestsModel model;
#Autowired
private ExternalRequestsProvider provider;
#EventListener(ApplicationReadyEvent.class)
public void onApplicationReady(ApplicationReadyEvent event) {
// do your process
}
}

Is There Any Way To Scan All #Component like Annotated Class After Spring ApplicationContext Load

I want to add #Component classes to spring container after ApplicationContext load. But I cannot use BeanFactory. Because I'm using BeanFactory I have to define beans for these classes. But I cannot defined it(If I am not use reflection). Because these classes will load at runtime by ClassLoader.
For example
#Component
public class Service {
private final CustomerService customerService;
private final OrderService orderService;
private final PaymentService paymentService;
#Autowired
public Service(CustomerService customerService, OrderService orderService, PaymentService paymentService) {
this.customerService = customerService;
this.orderService = orderService;
this.paymentService = paymentService;
}
}
In this example Spring create bean for this class while application invoking. There is no need to define bean with #Bean. But what I want is compile spring projects and load those clasess from another project and add to Spring ApplicationContext. So i can autowire these. Otherwise I have to create bean with reflection at runtime. And if I use reflection, I have invoke all dependent class recursively.
Is there any way do it without create beans using reflection at runtime.
If I understand things correctly: you have some classes that are marked with #Component and you want Spring to manage their lifecycle?
Does this help: https://springframework.guru/spring-component-scan/ ? #ComponentScan specifically or in XML config something like:
<context:component-scan base-package="org.example"/>
I found a solution.
ConfigurableApplicationContext context = SpringApplication.run(EventServiceApplication.class, args);
// Load class ...
context.start();
If we run context.start() method after load class, spring create #Component like class beans and put to spring container.
Another solution (This is exact solution):
ConfigurableApplicationContext context = SpringApplication.run(EventServiceApplication.class, args);
List<Class<?>> classes = // load classes
classes
.stream()
.filter(clazz -> clazz.isAnnotationPresent(Component.class) || Arrays.stream(clazz.getAnnotations()).anyMatch(annotation -> annotation.annotationType().isAnnotationPresent(Component.class)))
.forEach(applicationContext::register);
After register the classes, maybe one of your loaded class annoteded with #Configuration and it contains #Bean annotated methods. For register those #Bean methods. You should use
ConfigurationClassPostProcessor configurationClassPostProcessor; // This class is autowireable. Spring has bean for this class at spring bean container.
configurationClassPostProcessor.processConfigBeanDefinitions(applicationContext.getDefaultListableBeanFactory())
I found this solution at Spring Framework source code

Spring #Autowired not working in some classes

So i am using Spring to access my DB and fetch Users based on different Properties. With a #Restcontroller I get the Data. I created a UserRepository which extends the CrudRepository.
import org.springframework.data.repository.CrudRepository;
public interface UserRepository extends CrudRepository<User, Integer> {
Iterable<User> findByNachname(String nachname);
Iterable<User> findByRolle(Rolle rolle);
Optional<User> findByBenutzername(String benutzername);
#Transactional
String deleteByBenutzername(String benutzername);
}
I use #Autowire to get an Instance of the UserRepo in my Controller-class
#RestController
public class LoginController {
#Autowired
private UserRepository userRepository;
}
This works perfectly fine in all Controllers i have.
But now when i try the same in another class the userRepository Instance is null.
public class Authentificator {
#Autowired
private UserRepository userRepository;
}
The Authentificator and the LoginController are not in the same package. But both of them are not in the same package as the UserRepo.
project
UserRepo-package
Controller-Package
Authentificator-Package
you must make sure Authentificator is also a spring bean - I mean you must annotate it with something like #Component or #Service. After this step you’ll also have to “get” the Authentificator instance from spring instead of instantiating it with the new keyword.
#Autowired does work only with the spring context. This means that it will work only with class instances which are managed by Spring. Your Authentificator class is managed by you and Spring does not have to take care or know about it, it's not important for the Java Framework.
This is more of a configuration issue rather than an annotation issue.
If you want Spring to inject a field in Authenticator object the dependent object must be also created by Spring. You can do it by marking this class as a #Component or by creating a method with Authenticator return type marked with #Beanannotation. Then it must be injected somewhere.

How to Autowire a Spring-annotated service class in a #Configuration class?

I'm trying to inject a service-annotated class into a configuration class in a Spring Boot application, but it doesn't get injected (is set to null), which I assume is due to the Spring lifeycle.
Also, this service has an overloaded constructor that uses constructor injection, and I guess this is also a problem, as autowiring acts upon a default constructor. However, the service needs to be Spring-configured, so I don't think one can create a new instance in a Bean annotated method.
How can one solve this?
#Configuration
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private SessionService sessionService;
#Bean
public SessionService sessionService() {
return sessionService;
}
}
public interface SessionService extends BaseCacheService<Session> {
void extendExpiration(String key);
String getSessionId(String key);
}
#Service
public class SessionServiceImpl implements SessionService {
private Environment environment;
private UserService userService;
#Autowired
public SessionServiceImpl(Environment environment, UserService userService) {
this.environment = environment;
this.userService = userService;
}
}
If I exclude the #Bean method, then I get a compilation error:
Your error is the following (you are returning a null value):
#Bean
public SessionService sessionService() {
return sessionService;
}
Solution
Since your SessionServiceImpl is annotated with #Service, you can just remove the #Bean method and let spring create it. Spring already makes it available for you.
Or, If your SessionServiceImpl wasn't annotated with #Service, you would need the following :
#Bean
public SessionService sessionService() {
return new SessionService();
}
If this doesn't work, it may just be that your SessionServiceImpl is in a package not being scanned by spring (as suggested by #Miloš Milivojević)
You may add #ComponentScan to your Configuration class
#Configuration
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
#ComponentScan("com.package.to.sessionServiceImpl-or-higher")
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
Expanding on #Alex's answer, when you annotate a method with #Bean, it tells Spring that this method will produce that type. So, you essentially told Spring to give you the null reference you already had for all Beans of type SessionService.
If you are using Annotation-based context configuration, you can Autowire any #Component Bean (not just #Service) that can be constructed without runtime parameters (e.g. has a default constructor or an Autowired Constructor). If you need to do something to create the bean (e.g. runtime configuration required), you would either create a method as #Alex suggested, or you can use getBean and pass in the Type and Constructor arguments. The former is generally preferred.
I was facing similar issue while writing an integration test class for a spring boot application. RestTemplate class and CounterService of metrics API are autowired in my service class. I could use #ContextConfiguration(Classes={RestTemplate.class}) for injecting RestTemplate to my service, but adding CounterService.class to above annotation does not help, maybe because CounterService is an interface not a concrete class, Hence I was getting "No bean of type CounterService found" issue.
Thanks to answer by Milos, I included #EnableAutoConfiguration to my integration test class, issue was resolved!
If Alex's answer does not work (removing the #Bean method), you're probably not using #EnableAutoConfiguration or your Application is not in the root-hierarchy package so it's not scanning the whole classpath. Try adding #ComponentScan("service.class.package") to your configuration (in addition to removing the sessionService method) and see if it helps.

can I inject objects directly to a servlet using #Autowired somehow?

I have some servlets and some websocket servlets in my java application.
I use latest stable spring framework.
what I know is that because the servlets are not called by a different bean so they are not injectable and I need to get the applicationContext and use getBean to get the required objects.
is it true?
or can I use #Autowired in servlets somehow ?
so I want to be able to do the following:
#ServerEndpoint(value="/ServConnect")
public class ServConnect {
#Autowired UserDb userDb;
Instead of
#ServerEndpoint(value="/ServConnect")
public class ServConnect {
UserDb userDb;
public void ServConnect() {
// get application context somehow
userDb = appCtx.getBean("userDb");
}
thank you

Categories