I have this Spring component which I want to call from several locations in Java web application:
#Component
public class NotificationListener {
public void notificationProcess(TransactionsBean ro) {
// some code
}
}
Can I use it as a normal object in Spring or I should use other way to call the Spring code?
What you can do is retrieve the current ApplicationContext by implementing ApplicationContextAware and lookup the bean yourself with getBean.
Another thing you can try is autowire like you're used to with #Autowired and then use the following utility from Spring:
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
Related
I have a service-client project which is in normal spring application , not spring boot .its used for mainly logging related things.which contains Interceptor , loggingservice impl class and some model classes for logging. I have added this module as a dependency to main application in pom.xml.and i was able to inject and use the loggingService beans within the service layers of the main application.
Am getting NullPointerException while auto-wiring loggingService within the interceptor .The bean is not available within the interceptor.but like i said it can be injected and used within the main application.
Also am not able to read properties using #Value within the interceptor.
This is my Interceptor class .
#Component
public class LoggingInterceptor extends HandlerInterceptorAdapter {
#Autowired
LoggingService loggingService;
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws Exception {
loggingService.info("Am in prehandle");
return true;
}
}
This is my configuration class where i register the interceptor with the main application
#Component
public class LoggingConfig implements WebMvcConfigurer {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(getLoginInterceptor());
}
#Bean
public LoggingInterceptor getLoginInterceptor() {
return new LoggingInterceptor();
}
}
My question is almost similar to this post Cannot Autowire Service in HandlerInterceptorAdapter , but its different like am referring the interceptor from another module , and like they suggested i tried to create the bean from the application.
But the issues am facing right now is
getting NullPointerException while injecting loggingService within interceptor, but its working in main application
#Value annotation also return null, not able to read from properties
You have 2 possible solutions.
Mark your LoggingConfig as #Configuration instead of #Copmponent
Inject the LoggingInterceptor instead of referencing the #Bean method
Option 1: LoggingConfig as #Configuration
Your LoggingConfig is marked as an #Component whereas it should be marked as an #Configuration. The difference is that whilst it is allowed to have an #Bean method on an #Component it operates in a so-called lite mode. Meaning you cannot use method references to get the instance of a bean (this is due to no special proxy being created). This will lead to just a new instance of the LoggingInterceptor being created but it isn't a bean.
So in short what you are doing is equivalent to registry.addInterceptor(new LoggingInterceptor()); which just creates an instance without Spring knowing about it.
When marking the LoggingConfig as an #Configuration a special proxy will be created which will make the LoggingInterceptor a proper singleton bean, due to the method call being intercepted. This will register the bean in Spring and you will be able call the method.
NOTE: You actually endup with 2 instances of the LoggingInterceptor one due to the #Component on it the other through the #Bean. Remove the #Component.
Option 2: Inject the LoggingInterceptor.
As your LoggingInterceptor is marked as an #Component Spring will already create an instance (you actually have 2 instances of it created in your current setup). This instance you can inject into your LoggingConfig.
#Component
public class LoggingConfig implements WebMvcConfigurer {
private LoggingInterceptor loggingInterceptor;
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loggingInterceptor);
}
}
With this you can remove the #Bean method as you will get the proper one injected into your LoggingConfig class. The class can also remain an #Component in this case. Although I would recommend using #Configuration as to also properly stereotype it.
NOTE: If you are on a recent Spring version you can use #Configuration(proxyBeanMethods=false). This will make a lite-configuration (just like an #Component) but it is still marked properly as a configuration class.
I have a custom Stored Procedure class which is extending jdbc.StoredProcedure but I have annotated this class with Spring #Component to bring this class bean into Spring context.
Why I am doing this?
I wanted to add spring-retry on execute method which will work only on spring components
I wanted to reused the compiled StoredProcedure instead of creating a new object and recompiling every time, in this way I can reuse the compiled StoredProcedure every time.
anything wrong with this kind of implementation?
are there any issues we may see with this Spring component based StoredProcedure?
Ex:
#Component
public class ExampleStoredProcedure extends StoredProcedure {
#Autowired
private DataSource dataSource;
#Postconstruct
public void init() {
super.setDataSource(dataSource);
setSql("stored_procedure_name");
//TODO declare parameters
compile();
}
public void execute(){
//Todo set all parameters to ParameterSource
super.execute(parameterSource);
}
}
Try implementing a layered application architecture where you annotate your services with spring retry like this example:
https://dzone.com/articles/spring-retry-way-to-handle-failures
These service methods can define transaction boundaries and call your data persistence layers methods that could be based on spring data's standardized ways to call stored procedures and manage your database connections etc.
See for more info on Spring and architecture for example this brief introduction:
https://www.petrikainulainen.net/software-development/design/understanding-spring-web-application-architecture-the-classic-way/
I am getting the following error in a Spring Boot project on which I work:
The bean 'auditLogDao' could not be injected as a '{redactedpathwithcorporatename}.AuditLogDao' because it is a JDK dynamic proxy that implements:
org.springframework.data.jpa.repository.JpaRepository
Action:
Consider injecting the bean as one of its interfaces or forcing the use of CGLib-based proxies by setting proxyTargetClass=true on #EnableAsync and/or #EnableCaching.
I have tried a variety of solutions on StackOverflow without success, specifically:
Checking that I am indeed calling the interface, not the implementation.
Adding #Component to the top of SwitchUserFilter
Changing #Resource to #Autowired.
AuditLogDao.java
public interface AuditLogDao extends JpaRepository<AuditLog, String> {}
AuditLogService.java
public interface AuditLogService {
AuditLog save(final AuditLog auditLog);
}
AuditLogServiceImplementation.java
public class AuditLogServiceImplementation implements AuditLogService{
#Resource private AuditLogDao auditLogDao;
#Override
public AuditLog save(AuditLog auditLog) {
return auditLogDao.save(auditLog);
}
}
The file where I actually want to use the service to save information
SwitchuserFilter.java
public class SwitchUserFilter
extends org.springframework.security.web.authentication.switchuser.SwitchUserFilter {
#Resource AuditLogService logService;
'''
logService.save(auditLog);
'''
}
I am relatively new to Spring Boot, so an explanation of why it fixes the problem would be appreciated.
I believe the following code will solve your problem. Add it to the AuditLogServiceImplementation and remove the #Resource annotation from the auditLogDao.
#Autowired
private ListableBeanFactory beanFactory;
#EventListener({ContextRefreshedEvent.class})
void contextRefreshedEvent() {
auditLogDao = beanFactory.getBean(AuditLogDao.class);
}
You can do a similar trick in the filter too, whatever more comfortable for you.
I don't know what is the exact problem, but it's some kind of circular-dependency-like issue.
So by manually importing any bean which is affected in this loop, you can resolve the loop. You will set this one particular dependency AFTER Spring had created all of the other beans.
I'm new to Spring and am using an existing Spring library/api. All beans are configured in java classes, ie. no xml, and the existing configuration comes with one line in the main method:
SpringApplication.run(ServerExchange.class, args);
The library deals with the protocols to interface with a private server, I've been able to create normal instances of classes, ie:
AccountManager aM = new AccountManager()
however the configuration that's meant to be autowired into each class, such as the AccountManager, isn't being done as it's intended to be created as a "bean", so when I go to use the AccountManager, it's dependencies that are #Autowired are null
I've been looking online and trying to find an example of how to go from the first given line in the main method however what I can find online is mainly based around either xml or an "ApplicationContext". I'm not sure how to take the first step and simply create a bean, can anyone please provide an example of the code to create an AccountManager bean?
Thanks in advance.
Edit:
To clarify, I'm interested in the code required in the main method of how to get the instance of it once the beans have been set up in their respective classes.
If you want to configure been at class, you can do it as follow.
#Configuration
public class AppConfig {
#Bean
public AccountManager accountManager() {
return new AccountManager();
}
}
Or If you wanna use xml then
<beans>
<bean id = "accountManager" class = "packageName.AccountManager" />
</beans>
Then you can use it in a class as follows.
#Autowired
AccountManager accountManager ;
To create a bean of AccountManager do following:
#Bean
public AccountManager accountManager() {
return new AccountManager();
}
If you need any field to be autowired in an object you cannot instantiate it with new because when you do so Spring don't know about it.
You can do the following :
class MyClass{
#Autowired
ApplicationContext applicationContext;
public void method(){
AccountManager ac = applicationContext.getBean(AccountManager.class);
}
}
if your AccountManager is known by Spring. With an annotation on the class like #Component
As I'm not a user of Spring-boot in this way I found here : How to get bean using application context in spring boot how to get ApplicationContext in a different way than the one I'm using
I have a problem with injecting a bean into a helper class. It works basically like this: I create an object in the page constructor that does some work, returns some data and I show these on the page. In this helper object, a service should be injected via #Autowired annotation. However, I always get a null pointer exception when I use it. I also tried #SpringBean but it didn't help. On the other hand, when I inject this service directly into the page with #SpringBean, it's accessible and works fine. Do you know where the problem is?
This is the page:
public class Page extends BasePage {
public Page() {
HelperObject object = new HelperObject(new Application("APP_NAME"));
String result = object.getData();
add(new Label("label", result));
}
}
Helper object:
public class HelperObject {
private Application app;
#Autowired
private Service service;
public HelperObject(Application app) {
this.app = app;
}
public String getData() {
// use service, manipulate data, return a string
}
}
You can inject dependencies into non-Spring-non-Wicket-new-created objects using #SpringBean by calling InjectorHolder.getInjector().inject(this); in its constructor.
For example:
class MyPojo {
#SpringBean
MyDumbDAO dao;
MyPojo() {
InjectorHolder.getInjector().inject(this);
}
void justDoIt() {
dao.duh(); // dao is there!
}
}
Note that it will only work if called within a Wicket-managed request. If not (ie, if it's a Quartz job, or a Filter executed before Wicket's), the Application instance will not be available, and the injector won't know how to get the dependencies.
Another solution is to use Spring's #Configurable. It uses AspectJ to intercept creation of annotated objects, and inject its dependencies, even if you instantiate them directly with new (or some other framework, like Hibernate, creates them internally). But this requires runtime or build-time (works better for me) bytecode manipulation, which may be too much magic for some people.
#SpringBean only injects dependencies into classes that inherit from Wicket's Component. #Autowired only injects dependencies into classes created by Spring itself. That means you can't automatically inject a dependency into an object you create with new.
(Edit: you can also add a #SpringBean injection to your class by injecting in the constructor:
InjectorHolder.getInjector().inject(this);)
My normal workaround for this is to use my application class to help. (I'm a little puzzled by your use of new Application(...). I assume this isn't actually org.apache.wicket.Application.) For example:
public class MyApplication extends AuthenticatedWebApplication implements
ApplicationContextAware {
private ApplicationContext ctx;
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.ctx = applicationContext;
}
public static MyApplication get() {
return (MyApplication) WebApplication.get();
}
public static Object getSpringBean(String bean) {
return get().ctx.getBean(bean);
}
public static <T> T getSpringBean(Class<T> bean) {
return get().ctx.getBean(bean);
}
....
}
In my Spring application context:
<!-- Set up wicket application -->
<bean id="wicketApplication" class="uk.co.humboldt.Project.MyApplication"/>
My helper object then looks up the service on demand:
public class HelperObject {
private Service getService() {
return MyApplication.getSpringBean(Service.class);
}
The best practice would be to create your objects via a factory bean (that has those properties injected by Spring, and have that factory inject those properties to objects it spawns - pure IoC).
You should really avoid using SpringContext all over the place (or any other similar solution for that matter).
Here is a partial list of reasons:
Your code gets coupled with Spring way too much (low-cohesion).
You mix plumbing code with the business-logic.
Your code is less readable.
It's less maintainable (e.g., changing the name of the service bean would lead to code modification - this violates SRP & OCP).
It's less testable (e.g., you need the Spring framework to test it).