Is there a way to autowire an object that needs to be re-instantiated frequently?
I am using Netflix's DGS + spring boot framework, and basically storing the user authentication details in a custom context which is created for each request. I am trying to avoid adding context to the method signature because of the large amount of refactoring needed.
e.g.
public Result dataFetcher(DataFetchingEnvironment dfe) {
// this context contains user details which is used for authorization
// instantiated for every request
setRolesInContext(dfe);
MyCustomContext context = DgsContext.getCustomContext(dfe);
// trying to avoid adding context as an extra param e.g. dataFetcherHelper(context)
dataFetcherHelper(); // this calls other helper methods from other classes
}
I was thinking of using the facade pattern but this would not be thread safe. Basically autowire the RequestContextHolder, and call setRequestContext each time a new context gets initialized.
#Component
#NoArgsConstructor
#Getter
#Setter
public class RequestContextHolder {
private RequestContext requestContext;
}
I'm not sure how your question:
Is there a way to autowire an object that needs to be re-instantiated frequently?
Is related to the use case that you've presented in the question...
From the question it looks like you can consider using ThreadLocals as a conceptual "substitution" to the global variable available all over the place in the request if you don't want to add parameters to the methods to propagate the context through the flow.
This will work only in "thread-per-request" model, it won't work for reactive systems and for the complicated cases where you maintain different thread pools and switch the threads while implementing the Business Logic on backend:
So to achieve "thread-safety" in your context holder that you have suggested you can use:
#Configuration
public class MyConfig {
#Bean
public ThreadLocal<MyCustomContext> ctxHolder() {
return new ThreadLocal<>();
}
}
Then, again, if you're working in thread-per-request model, you can:
#Component
public class DataFetcherInterceptor {
#Autowired
private ThreadLocal<MyCustomContext> ctxHolder;
public Result dataFetcher(DataFetchingEnvironment dfe) {
// this context contains user details which is used for authorization
// instantiated for every request
setRolesInContext(dfe);
MyCustomContext context = DgsContext.getCustomContext(dfe);
ctxHolder.set(context);
dataFetcherHelper();
}
}
In the dataFetcherHelper or in general in any method that requires the access to the context you can:
public class SomeService {
#Autowired ThreadLocal<MyCustomContext> ctxHolder;
public void dataFetcherHelper() {
MyCustomContext ctx = ctxHolder.get();
}
Now, I see that dataFetcherHelper is just a method that you call from withing this "interceptor" class, in this case its an overkill, but I assume, you've intended that this is actually a method that belongs to another class, that might be an element in the call-chain of different classes. For these situations, this can be a working solution.
Related
First, forgive my poor English, I am just working hard on my English:).
I'm trying to find an easy way to set the communication more simple between front-end and back-end, because I use ActiveMQ as the Message Oriented Middleware. So XML string became the request carrier.
For example, front-end send a string request to back-end including package name, class name, method name and parameters list, in this way, back-end is allowed to invoke the correct method by these information, and send invoke result back to front-end. It works, but not perfect. The problem is that when I tried to invoke a method in a service class with #Transational and #Service annotation(which is the common practice to connect to the database),the transaction seemed not being opened, request and response are both received, just left a lot of sleeping connection in mysql database process, as much as the ActiveMQ's consumers every time.
Target method in service class:
#Service
#Transactional
public class UserService {
#Autowired
private IUserDAO udao;
public User getUserByName(String username) {
return udao.findByUsername(username);
}
}
Invoke method(some code has been omitted):
#Component
public class ReflectTool {
public Object invokeMethod(String packageName,String className,String methodName,List paramList) {
BeanFactory beanFactory = new ClassPathXmlApplicationContext("applicationContext.xml");
Object obj = beanFactory.getBean(packageName+"."+className);
Class cla = obj.getClass();
Method method = findMethod(Class cla,String methodName);
return method.invoke(obj, params);
}
}
I've searched a lot answer, but none of them worked. Like:use a proxy object to invoke but not the target object, cause spring framework has used a proxy class instead the service class with #Transactional annotation to help we manager the transaction, but the code (AopUtils.isAopProxy(obj)) returns true, so it mean the object is exactly a proxy object which I got from the spring context? I'm not very familiar with Dynamic Agent Model.
Thanks for your attention, please tell me if I did something wrong.
Well I was going to this I'd try the following approach:
DON'T use BeanFactory, inject in your ReflectTool the ApplicationContect: #Autowired private ApplicationContext applicationContext; if the beans you want to recover implements some interface or extends a class then maybe you can replace this injection by a Map. Spring will make it work
Try to get the object of the bean you need.
the lines you have regarding the capture of the method and execution should work since it is an bean calling another bean.
Hope this helps. I had a similar situation where I needed to invoke a #Transactional method and I fixed in a similar way I have described.
I love dependency injection frameworks and how they allow me to request the one object everything starts with. All the wiring is made on the first request for that "master" object.
However, there are objects that should be created during runtime, e.g. based on user input. And sometimes those newly created objects should be shared among other objects created by the framework.
My current approach is to have "uninitialized" objects injected by the framework. During runtime I set up the object with setter methods as soon as possible.
What I don't like with this approach is that the setter methods are really invoked only once and should then never be touched again. This prevents me from declaring the fields as final. I don't now how to create the object not before all necessary information is available without losing all the benefits from the DI framework.
I'm new to DI. Are there any good patterns for this?
Example:
// The service is used through out the application
interface Service {
makeRequest()
}
What I want to do after user typed in credentials:
new ConcreteService(username, password)
// but now I need to inject the concrete servive manually everywhere I need it!
What I'm currently doing:
interface Service {
makeRequest()
setCredentials(username, password)
}
// service can be injected by framework, but I don't like setter methods
// that much (and they can pollute the interface)
Most of my experience with dependency injection is with C# but I believe the concept remains the same no matter what language.
What I understand from the original poster is that he's trying to "persist" information within the dependency injection container in order to retrieve the information at a later time.
The problem with this approach is that, in a multi-threaded scenario, there's the possibility that the dependency that you are using to persist information has its values overwritten by another thread. This can happen because the dependency injection container usually holds a single instance of the object which is returned to you whenever you need it. Therefore, you need to make sure that your design is thread safe.
In my experience, using the dependency injection container to maintain state is bad.
What you register in your dependency injection container are the objects that provide a "service" and that don't maintain any state.
Objects that you use to hold information are usually business objects. These business objects should just be instantiated with "new" (without the dependency injection container), populate them in the usual manner (with setters or initialization method or constructor) and just be passed on as part of the signature of the operations that your services expose.
Note: You can register your dependency as "transient" which would tell the dependency injection container to return a new instance every time you ask for the dependency. This would avoid the need to use the "new" keyword explicitly and give you more control when writing unit tests with a mocking framework.
Hope this helps!
One way you could do it would be to use a factory.
For example, say you had this class...
public class UserBean {
private int userId;
private UserService userService;
// other resources / dependency fields etc
public UserBean(int userId, UserService userService, ...other dependencies...) {
this.userService = userService;
this.userId = userId;
this.... = ...
}
// ...getter for userId maybe etc...
// Some method that uses the user's data AND the component/service you want to inject from Spring...
public void incrementHitCount() {
userService.incrementHitCount(userId);
}
}
...where "userService" is something you want that is managed by the IoC container. If you then have a component that needs to create one of these, e.g....
#Component
public class UserHitCountIncrementerThing {
public ResponseBean doThatThing(HttpServletRequest request) {
int userId = request.<get the user Id from it...>
UserBean userbean = new UserBean(userId, /* need dependencies here! */);
...do stuff...
}
}
You could just #Autowire in all of the services to this bean, or you could create a factory and just #Autowire one, for example...
#Component
public class UserBeanFactory {
#Autowired
private UserService userService
//...other #Autowired dependencies...
public UserBean createUser(int userId) {
return new UserBean(userService, ...etc..., userId);
}
}
Now just use this where you need it, e.g...
#Component
public class UserHitCountIncrementerThing {
#Autowired
private UserBeanFactory userFactory;
public ResponseBean doThatThing(HttpServletRequest request) {
int userId = request.<get the user Id from it...>
UserBean userbean = userFactory.createUser(userId);
...do stuff...
}
}
Is this what you were getting at?
Hope this helps.
I'm using HK2 as part of a Jersey RESTful API. I'm working in an multitenant system, and in most of my API calls, the tenant is a path parameter. I also have several DAOs, which currently accept the tenantId in their constructor, such as:
public final class WidgetMapper {
public WidgetMapper(final int tenantId) { .. }
..
}
I'd like to use HK2 to provide my DAOs to the other layers of my application. What's the right way to do this?
Change the DAOs to use a setter rather than a constructor argument. Only .. ick. The tenantId is part of the required state of the DAO.
Add a layer of abstraction. Create <interface>MapperFactory and MapperFactoryImpl, which has a no-arg constructor and a bunch of getters, such as getWidgetMapper and getGizmoMapper. Only .. this seems cumbersome. I'd rather not have to maintain these extra classes.
Is there some magic way for HK2 to inject that int value into the WidgetMapper constructor at runtime? Then I could inject the tenantId into the mapper, and the mapper into my other classes.
?? Other HK2 magic?
You need to extract the tenant ID from the path parameter in the request, so as long as it's OK to instantiate your DAOs for each request, you can implement a Factory.
public WidgetMapperFactory implements Factory<WidgetMapper> {
private final ContainerRequestContext containerRequestContext;
#Inject
public WidgetMapperFactory(ContainerRequestContext containerRequestContext) {
this.containerRequestContext = containerRequestContext;
}
public WidgetMapper provide() {
UriInfo uriInfo = containerRequestContext.getUriInfo();
List<String> matchedUris = uriInfo.getMatchedURIs();
int tenantId = 1; // Actually work it out from the matched URIs
return new WidgetMapper(tenantId);
}
public void dispose() {
// Do any clean up you need
}
}
Then bind the factory:
public MyResourceConfig extends ResourceConfig {
public MyResourceConfig() {
register(new AbstractBinder() {
#Override
protected void configure() {
bindFactory(WidgetMapperFactory.class).to(WidgetMapper.class).in(RequestScoped.class);
}
});
}
}
You can then inject WidgetMapper in a Resource class, and the WidgetMapper doesn't have any knowledge it's being used in a web service.
Change the DAOs to use a setter rather than a constructor argument.
Only .. ick. The tenantId is part of the required state of the DAO.
If your DAOs are singletons I don't see how this would work (or at least how it could be done cleanly).
What's the right way to do this?
IMO, I think the best approach is to have 1) singleton DAOs 2) some type of proxy that got injected into the DAOs when they were instantiated by HK2 and then provided the correct tenant id for the current thread.
I can think of two ways to do this:
Option 1:
I haven't tried it, but I think you could probably inject UriInfo into your DAOs, either through the constructor, a private field, or setter. You could extract the tenant id for the current request from the UriInfo instance.
If I were you, I'd create an abstract class for my DAOs that got a UriInfo injected into a private field. I'd then provide a protected method to return the current tenant id from uriInfo.getPathParameters
public abstract class AbstractDao {
// jersey/hk2 provides a proxy that references the current thread-bound request
#Context
private UriInfo info;
protected int getTenantId()
{
// always returns the tenant id for the current request. TODO: add
// logic to handle calls that don't have a tenant id.
return Integer.valueOf(info.getPathParameters.getFirst("tenantId");
}
}
Option 2:
?? Other HK2 magic?
You could write a custom injection resolver.
One more idea...
Option 3:
This one doesn't directly answer your question since it doesn't use HK2 to inject the tenant ID into the DAOs but I think it's worth mentioning.
You could implement your own ContainerRequestFilter that obtained the tenant id and provided it to other components in your app.
By default, Jersey will invoke the filter after it resolves the resource method but before the method is actually invoked. You can obtain a UriInfo from the ContainerRequestContext, get the tenant id path param, then stuff that param into your own thread local variable. You could then reference the thread local within your DAO. Again, I recommend adding a protected method in a base DAO class to encapsulate this logic.
in most of my API calls, the tenant is a path parameter
Optionally, you can use NameBinding to control the behavior described above.
If you wanted to, you could implement option 3 using a regular ServletFilter instead.
Note:
After I wrote this answer, I realized that I assumed you were comfortable extending ResourceConfig, that you knew how to obtain an instance of ServiceLocator, and that you were comfortable with adding your own bindings. If you're not, let me know and I'll edit my answer to provide more details.
I am new to Guice and have a question regarding caching.
I have a WebApp which uses a provider to provide user configurations.
bind(UserConfiguration.class).toProvider(UserConfigurationProvider.class).in(ServletScopes.REQUEST);
The provider is declared as:
public class UserConfigurationProvider implements Provider<UserConfiguration>{
public UserConfiguration get() {
userConfigurationDatabase.getUserConfiguration(<some param here>);
}
}
In the get method, it calls DB and make a very expensive DB call.
I have a number of classes which get UserConfiguration injected like:
public class PriceView {
private UserConfiguration userConfiguration;
#Inject
public MyClass(UserConguration userConfiguration){
this.userConfiguration = userConfiguration;
}
.....
}
public class OrderView {
private UserConfiguration userConfiguration;
#Inject
public MyClass(UserConguration userConfiguration){
this.userConfiguration = userConfiguration;
}
........
}
The problem is that every time I switch a view, a new xxxxView object is created and hence a new UserConfiguration is injected and hence the expensive DB call is called.
I want to make calling the DB limited to once per user login. My idea is that cache the UserConfiguration somewhere when a user login and clear it after user logout or it expires.
But I want to know whehter Guice offers something more clever ways of caching about this use case?
Many thanks.
If you're using standard servlet session, then it should be enough to use ServletScopes.SESSION scope instead of ServletScopes.REQUEST. In this case the injected object should be created only once per session.
However, if you are not using standard servlet session but something custom, then you also need to create custom scope.
I have a jax-ws web service with several handlers. I have a particular object that is performance wise costly to initiate. I need this object to process each and every request come to web service.
Is it a solution to put this object to a static block? Since static block is created at class loading time will it give a performance improvement. But still does it achieve what I need. I need same object kept in the memory and reused for all requests. But as I know in a web service each request is allocated to a thread object in the static block will not be shared by threads. it is?
Expecting a bit of explanation here guys.
Thank you
A static block is a piece of code which is run once when the class is initialized by the class loader. You might use it to set up your complex object and then keep a reference to it in a static variable like so:
public class MyClass {
private static final LanguageLookup languageLookup;
static {
languageLookup = new LanguageLookup ();
languageLookup.loadData();
}
public Response handleRequest(Request request) {
String language = languageLookup.lookup(request.getCountryCode());
response.setLanguage(language);
return response;
}
}
If you do this in a multi-threaded environment like a servlet or a webservice you need to be sure that the state of LanguageLookup cannot change after its initialization. If it uses dependencies of its own for operations other than its initialization, these must also be stateless.
I think it is generally not a good idea to do it this way because you are hard-wiring your class to the LanguageLookup, making it tightly coupled and harder to unit test.
It is very easy to use a dependency injection framework like Spring to set up singletons:
When a bean is a 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.
In the application context you would have something like:
<bean name="languageLookup" class="com.acme.foo.LanguageLookup" singleton="true" init-method="loadData"/>
And in your code:
public class MyClass {
private LanguageLookup languageLookup;
public Response handleRequest(Request request) {
String language = languageLookup.lookup(request.getCountryCode());
response.setLanguage(language);
return response;
}
// called by Spring
public void setLanguageLookup(LanguageLookup languageLookup) {
this.languageLookup = languageLookup;
}
}