Is this possible to define a Spring bean in applicationContext.xml that takes an instance of HttpRequest as a constructor argument?
The bean I'm trying to create is an instance of org.keycloak.adapters.springsecurity.facade.WrappedHttpServletRequest. The reason behind this is that I want to use Spring AOP to intercept a method that's invoked from that class. Is this possible?
That's the constructor code:
public WrappedHttpServletRequest(HttpServletRequest request) {
Assert.notNull(request, "HttpServletRequest required");
this.request = request;
}
Related
If I have a bean definition with some configuration within it and I use autowire to get an instance of the same class, is it the instance of the bean definition I get returned or a new instance of the class without any configurations?
class Name {
private fName;
private lName;
constructor(string fName, string lName) {
this.fName = fName;
this.lName = lName;
}
}
#Bean
public Name getName() {
Name test = new Name(thisIsMyFirstName, thisIsMyLastName);
}
--Separate File--
#Autowired
private Name testName;
Is testName here a copy of the #Bean getName() (has thisIsMyFirstName and thisIsMyLastName set) or is it a new instance of the class Name without a first name of thisIsMyFirstName and last name of thisIsMyLastName?
By default, yes, beans are singletons.
But, the Spring framework defines a number of different scopes.
singleton
Scopes a single bean definition to a single object instance per Spring IoC container.
prototype
Scopes a single bean definition to any number of object instances.
request
Scopes a single bean definition to the lifecycle of a single HTTP request; that is each and every HTTP request will have its own instance of a bean created off the back of a single bean definition. Only valid in the context of a web-aware Spring ApplicationContext.
session
Scopes a single bean definition to the lifecycle of a HTTP Session. Only valid in the context of a web-aware Spring ApplicationContext.
global session
Scopes a single bean definition to the lifecycle of a global HTTP Session. Typically only valid when used in a portlet context. Only valid in the context of a web-aware Spring ApplicationContext.
The scope of a bean can be change using the #Scope annotation.
#Bean
#Scope("singleton") // <- singleton is the default. If no #Scope annotation is present, this is what is used.
public BeanA sharedBean() {
// This will only be called once, all subsequent calls will return from the cached reference in the ApplicationContext
return new BeanA();
}
#Bean
#Scope("prototype")
public BeanB privateBean() {
// This will be called every time the bean is injected and a new instance returned.
return new BeanB();
}
This is just another syntax
#Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
Would it be technically a good and acceptable practice to inject required dependencies using an Interceptor type. For example:
public #interface Inject {
public Class thisType();
}
public class InjectionInterceptor implements HandlerInterceptor {
#Override
public bool preHandle(HttpServletRequest hsr, HttpServletResponse hsr1, Object o) {
HandlerMethod handlerMethod = (HandlerMethod) o;
Class type = handlerMethod.getBeanType();
Annotation[] annotations = type.getAnnotationsByType(Inject.class);
for(Annotation annotation: annotations){
Inject inject = (inject) annotation;
for(Field field :type.getDeclaredFields()){
if(field.getType().equals(inject.thisType())){
field.setAccessible(true);
field.set(handlerMethod.getBean(), Services.find(inject.thisType()));
}
}
....
return true;
}
...
}
A bean can have 4 scopes.
Singleton
Only one shared instance of the bean will be managed, and all requests for beans with an id or ids matching that bean definition will result in that one specific bean instance being returned by the Spring container.
It is default scope of a bean.
Prototype
New instance is returned by the container when bean with the specified id is requested.
Ex: If you have a bean with id as "employee" in your spring container, then everytime you do a
Employee emp = context.getBean("employee");
A new instance will be returned.
request, session, and global session are for use only in web-based applications
Request
A new instance is created for every single HTTP request.
Ex : Login needs different instance everytime.
Session
A new instance will be created of the bean using the bean definition for the lifetime of a single HTTP Session.
global
The global session scope is similar to the standard HTTP Session scope and really only makes sense in the context of portlet-based web applications
You can specify the scope of a bean in two ways
Using XML:
<bean id="employee" class="com.company.Employee" scope="singleton"/>
Using annotation.
mark the class with #Scope("prototype")
you can read more about scopes here
sample code for reference is available here
Is there a way where I can create a runtime bean on spring. I needed this to happen since the values of the bean will be injected by the external entity through RESTful service. Is it possible for the runtime bean to still be autowired?
It is perfectly possible
In your Controller (or in your Factory would be more elegant) you need to inject your Application context
#Autowired
private ApplicationContext applicationContext;
You can create your beans like this:
YourClassBean yourObject = this.applicationContext.getBean(YourClassBean.class, params);
In your Spring configuration do this:
#Bean
#Scope(value = "prototype")
YourClassBean yourClassBean(String params) {
return new YourClassBean(params);
}
And your are done.
In that example the Scope is Prototype which means that you will get a new object every time you call the method yourClassBean.
Also in that example the params are a String (it is like the initialization parameters of your bean, but that is totally optional, and of course you might need or want more parameters in there and it is totally find)
I was experimenting Spring's BeanPostProcessor, BeanFactoryPostProcessor, Initializing bean , destroy bean.
I'm confused with these notification concepts.
I created a simple bean implementing Initi*Bean, Disposable bean. And also registered sample post processor , factoryPostprocessor. And added sysout in all the interface methods.
I created AbstractApplicationContext and registered shutdown hooks as well.
When i ran the app, i see BeanFactoryProcessor method prints, AfterProperties method, and then destroy method called. I dont see "initializing bean" called..
Does BeanPostProcessor override the initializing bean notification?
Kindly explain.
You're returning null in both your BeanPostProcessor methods. This causes Spring to think you don't want any further processing on that bean, including initializing through InitializingBean.
Just return the original bean you receive (in both methods)
#Override
public Object postProcessAfterInitialization(Object bean, String arg1) throws BeansException {
System.out.println("postProcessAfterInitialization");
return bean;
}
since you don't want to process it.
I would like to be able to test a route which consumes from a queue then does some work in a bean involving a spring injected service and use mockito to effectively mock out this service.
My spring route is as follows:
<camel:route id="msgemailqueue-to-emailservice">
<camel:from uri="activemq:emails" />
<camel:bean ref="emailService" method="createEmailRequest"/>
</camel:route>
The emailService bean has an autowired service which is then called in the createEmailRequest() which goes off to another service and retrieves user data to be used subsequently.
The test:
#RunWith(MockitoJUnitRunner.class)
public class TroubledEmailServiceImplTest extends CamelSpringTestSupport {
#Produce(context = "messagingCamelContext")
protected ProducerTemplate producer;
#Mock
private UserRestService userRestService;
#Override
protected AbstractApplicationContext createApplicationContext() {
return new ClassPathXmlApplicationContext("messaging-camel-route-test-context.xml");
}
#Test
public void testUserResponseToEmailQueue() throws Exception {
context.addRoutes(new MyDynamcRouteBuilder(context, "direct:addEmailRequest", "activemq:emails"));
Mockito.when(userRestService.getUserById(Mockito.anyLong())).thenReturn(
new WebServiceResult<UserVO>(new UserVO()));
CreateMessageRequest msgReq = new CreateMessageRequest();
producer.sendBody("direct:addEmailRequest", msgReq);
Mockito.verify(userRestService).getUserById(Mockito.anyLong());
assertMockEndpointsSatisfied();
}
The bean as follows:
#Override
public void createEmailRequest(final CreateMessageRequest request) throws CreateEmailException {
LOGGER.trace("Entering createEmailRequest(request) " + Arrays.asList(new Object[] { request }));
Validate.notNull(request, "CreateMessageRequest was null");
WebServiceResult<UserVO> response;
try {
response = userRestService.getUserById(request.getId());
} catch (final WebServiceException e) {
throw new CreateEmailException("Error lookup up user data for email", e);
}
final UserVO userResponse = response.getData();
All compiles ok and when running the route fires as an object is popped on the queue which is then passed to the bean and the createEmailRequest is invoked and the call to the mockito mocked service happens ok
response = userRestService.getUserById(request.getId());
but the response is null even though
Mockito.when(userRestService.getUserById(Mockito.anyLong())).thenReturn(
new WebServiceResult<UserVO>(new UserVO()));
was performed in the test. It appears that the service in bean is a different instance i.e. mockito mock is never invoked.
I am doing something wrong and perhaps my testing approach is all wrong as well but should this work in theory? I'd really like to be able to mock out a service in a bean in my camel route.
I'm using Camel Enhanced Spring Test and have passed through the same issue. I only changed #Mock to #MockBean. My Camel version is 2.18.
the mock userRestService you create in the test has to be the same instance you use in the bean. I do not see where you are setting the userRestService for the createEmailRequest method. That service needs to be the same mock object as you create in your test.
I have resolved this - mea culpa. My test class was effectively creating two instances of the service - one through the spring application context and another due to the #RunWith(MockitoJUnitRunner.class) plus #mock annotation. Now resolved by doing the mock creation once. To sum up this was a spring wiring issue only on my part. Many thanks #mike-pone.