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
Related
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
}
}
I'm using spring-boot to start an HTTP server. It contains the following two files:
BeanUtils
#Service
public class BeanUtils implements ApplicationContextAware {
public static ApplicationContext cxt;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
cxt = applicationContext;
}
}
MainController
#RestController
public class MainController {
#GetMapping("/getData")
public Object getData() {
return BeanUtils.cxt.getBean("someBean").getData();
}
}
Does spring guarantee to finish all the beans, including both BeanUtils and MainController when the server starts? If not, the user might get a NullPointerException when he/she tried to access /getData because the BeanUtils bean hasn't been loaded. I want to know if it's safe to write like this.
you can try it. before send /getData request, BeanUtils has been loaded when server starts.
all the beans are instantiated on starting up in Spring IOC container, if it is a singleton bean(as are by default) an instance of bean is created at startup and passed wherever required and if not(prototype), an instance is created at the time required and passed. so in this case you won't get NullPointerException.
I have UserService and MissionService.
Is it ok to inject MissionService in UserSerivce or vice versa?
If yes, what about unit testing?
Of course you can and it is perfectly fine. But I recommend that you use method-injection in order to allow you to set the instance at runtime without using using reflection (you can create an instance manually).
For example:
#Service
public class MissionService { }
#Service
public class UserService {
private MissionService missionService;
#Autowired
public void setMissionService(MissionService missionService) {
this.missionService = missionService;
}
}
This allows you to create both services using regular Java without Spring:
MissionService missionService = new MissioNService();
UserService userService = new UserService();
userService.setMissionService(missionService);
Caution: You have to take care of not building dependency cycles. It is not set that Spring resolves them, I think
Instead of "struggling" to inject or pass common Spring beans everywhere it is needed, especially in non Spring managed class, is it a good practice to set the Spring's application context in a static variable to get it from anywhere ? Doing that allow for example to get the JdbcTemplate singleton in a non Spring managed class (or the Hibernate session factory). Is there good reason to not doing that ?
for example :
#Component
public class SpringContext implements ApplicationContextAware {
private static ApplicationContext applicationContext;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringContext.applicationContext = applicationContext;
}
public static JdbcTemplate getJdbcTemplate() {
return applicationContext.getBean(JdbcTemplate.class);
}
public static SessionFactory getSessionFactory() {
return applicationContext.getBean(SessionFactory.class);
}
public static Session getCurrentSession() {
SessionFactory sf = applicationContext.getBean(SessionFactory.class);
return sf.getCurrentSession();
}
}
In another class, not managed by Spring :
public class MyClass {
public Integer method1() {
String sql = "select 1 from dual";
Integer n = SpringContext.getJdbcTemplate().queryForObject(sql, Integer.class);
return n;
}
}
This seems counter to Spring's intended usage, and to the concept of dependency injection. Whilst you could do this, I think the better solution is to inject those beans where required.
I find it a good practice to initialise the context once, reference a 'root' bean, and that bean would essentially be the application and contain references (directly or indirectly) to every other bean in the system.
If you have a web application, you can use the class org.springframework.web.context.support.WebApplicationContextUtils from Spring. It provides a method to get the root WebApplicationContext.
What you want is a singleton, i.e., a class of which there exists only one instance, that is also a Spring managed singleton (a singleton scoped bean). I found a very elegant solution to this problem when I was using Spring a few years ago. Let's say your singleton looks like this:
public final class MySingletonClass{
private static MySingletonClass instance = new MySingletonClass();
public static MySingletonClass getInstance(){
return instance;
}
#Autowired
private JdbcTemplate jdbcTemplate;
#Autowired
private SessionFactory sessionFactory;
#Autowired
private DataSource dataSource;
// getters and other methods omitted
}
You can force Spring to manage this singleton simply by adding in your application context the following line:
<bean class="com.mypackage.MySingletonClass" factory-method="getInstance"/>
Now your singleton will have all the above Spring-managed objects autowired (if available in the context) and can be used by any non-Spring managed class:
class MyClass {
// Can only be called after Spring initialized.
void doSomething() {
DataSource ds = MySingletonClass.getInstance().getDataSource();
// ...
}
}
Every object that you believe needs to be an actual singleton can use the above pattern. This preserves the Spring approach to object life cycle management and dependency injection providing the safety of a true singleton object. Moreover, the singleton will be Spring managed so all its dependencies will be properly wired or the application will fail at application startup.
It seems you want beans that are not "managed by Spring" but have access to Spring beans.
Prototype scope exists for that purpose: you let Spring instantiate the class and inject any necessary dependencies, and then you control that bean's lifecycle yourself (Spring doesn't care about it anymore).
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.