In a Spring Boot application I'm using a class annotated with #KafkaListener as a message listener. I want to add a ConsumerRebalanceLister to my application to manage cached data on a rebalance.
How do I add a ConsumerRebalanceListener to a ConcurrentKafkaListenerContainerFactory. The documentation says that it should be set on a ContainerProperties object. It's not clear how to access that object in order to set it. Additionally, it looks like the ConcurrentKafkaListenerContainerFactory throws away the rebalance listener since it creates a new ContainerProperties object when creating a listener container instance.
I feel like I'm missing something really obvious here, before this commit there was a method to simply set the rebalance listener directly on the ConcurrentKafkaListenerContainerFactory.
Consider to use this method on the ConcurrentKafkaListenerContainerFactory:
/**
* Obtain the properties template for this factory - set properties as needed
* and they will be copied to a final properties instance for the endpoint.
* #return the properties.
*/
public ContainerProperties getContainerProperties() {
This is where you can add your ConsumerRebalanceListener. You #Autowired an auto-configured ConcurrentKafkaListenerContainerFactory and perform the mentioned injection:
#Autowired
private ConcurrentKafkaListenerContainerFactory containerFactory;
#PostConstruct
public void init() {
this.containerFactory.getContainerProperties()
.setConsumerRebalanceListener(myConsumerRebalanceListener());
}
#Bean
public ConsumerRebalanceListener myConsumerRebalanceListener() {
return new ConsumerRebalanceListener() {
...
};
}
Related
In my JSF application i have a process that takes to long to complete and i don't want that the user keeps waiting till its finish. I'm trying to implement some kind of 'fire and forget task' to run in background.
I'm doing it using an #Asynchronous method. This is the right approach?
My controller:
#ViewScoped
#Named
public class Controller implements Serializable {
private static final long serialVersionUID = -6252722069169270081L;
#Inject
private Record record;
#Inject
private Service service;
public void save() {
this.record.generateHash();
boolean alreadyExists = this.service.existsBy(this.record.getHash());
if (alreadyExists)
Messages.add(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Error", "This record already exists"));
else {
this.service.save(this.record);
this.clearFields();
}
}
}
My service:
#Stateless
public class Service extends AbstractService<Record> {
private static final long serialVersionUID = -6327726420832825798L;
#Inject
private BeanManager beanManager;
#Override
public void save(Record record) {
super.save(record);
this.preProcess(record);
}
#Asynchronous
private void preProcess(Cd cd) {
// Long task running here ...
this.beanManager.fireEvent(cd);
}
}
But even with this approach the user keeps stuck at the page till the preProcess method finishes.
The problem here is that annotations that modify the behavior of EJBs (and CDI beans) are only applied when called by the "proxy" object that gets injected to appropriate injection points, like fields annotated with #EJB or #Inject.
This is because of how the containers implement the functionality that modifies the behavior. The object that the container injects to clients of EJBs (and normal-scoped CDI beans) is actually a proxy that knows how to call the correct instance of the target bean (e.g. the correct instance of e #RequestScoped bean). The proxy also implements the extra behaviors, like #Transactional or #Asynchronous. Calling the method through this bypasses the proxy functionalities! For this reason placing these annotations on non-public methods is effectively a NO-OP!
A non-exclusive list of solutions:
Move preProcess() to a different EJB, make it public and keep the #Asynchronous annotation
Make preProcess() public and call it from the Controller
If the computation is truly private to the Service and exposing it would break design, and ou don't mind doing a bit more manual work, you can always run async tasks from the container-provided ManagedExecutorService:
#Resource
private ManagedExecutorService managedExecutorService;
Pay attention to the semantics of the thread that executes your code - more specifically to what context values are propagated and what not! Well, you have to pay attention to that for #Asynchronous methods too!
Trying to wrap my head around dependency injection, coming from the world of static classes and instantiated classes. Here is what I currently have:
[SomeFilter]
public class AController : Controller
{
private readonly IOptions<AppSettings> _appSettings;
public AController(IOptions<AppSettings> appSettings)
{
_appSettings = appSettings;
}
// GET: /characters/
public IActionResult Index()
{
//do something
}
SomeFilter gets called immediately, and does this:
public class SomeFilter: ActionFilterAttribute, IActionFilter
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
OtherClass.RunMe();
}
}
OtherClass looks like this:
public class OtherClass
{
private readonly IOptions<AppSettings> _appSettings;
public OtherClass(IOptions<AppSettings> appSettings)
{
_appSettings = appSettings;
}
public RunMe()
{
//do something
}
I also have OtherClass registered as a service.Singleton in the Startup.cs.
I get an error stating:
"An object reference is required for a non-static field"
for the OtherClass.RunMe(); call.
I was under the assumption that I can call this class from anywhere within my code instead of having to create a new instance of it? Essentially, how do I call methods from other classes using dependency injection?
You can't constructor injection on filters. It's all about run time order. When you try injection on constructor, your IoC container not reachable at the moment. You should be use property/setter injection.
I prefer using structuremap container for to do this. Because structuremap has very easy to apply any type injection. For example when you have a filter registry like this
public class ActionFilterRegistry : Registry
{
public ActionFilterRegistry(Func<IContainer> containerFactory)
{
For<IFilterProvider>().Use(
new StructureMapFilterProvider(containerFactory));
Policies.SetAllProperties(x =>
x.Matching(p =>
p.DeclaringType.CanBeCastTo(typeof(ActionFilterAttribute)) &&
p.DeclaringType.Namespace.StartsWith("YourNameSpace") &&
!p.PropertyType.IsPrimitive &&
p.PropertyType != typeof(string)));
}
}
And you register it on your global.asax(prefer) or one of your startup class.
Example app_Start method.
DependencyResolver.SetResolver(new StructureMapDependencyResolver(() => Container ?? ObjectFactory.Container));
ObjectFactory.Container.Configure(cfg =>
{
cfg.AddRegistry(new StandardRegistry());
cfg.AddRegistry(new ControllerRegistry());
cfg.AddRegistry(new ActionFilterRegistry(() => Container));
cfg.AddRegistry(new MvcRegistry());
});
Then you can use any filter with injection. But pay attention you shouldn't be use contructor injection like you do.
I found a way to inject into the filter by using
[ServiceFilter(typeof(MyFilter))]
instead of just
[MyFilter]
and within the filter's
(ActionExecutingContext context)
{
var controller = context.Controller as Controller.
controller.whateverIneed
}
This now provides me with what I need within the filter. What I also realized is that I can't remove the need for creating references to other classes using new, as I was under the impression Core's dependency was all about "no more new". This gets into fundamentals with Core which I'm still grasping with.
What I ended up doing was creating new classes that do some work, but they are setup as services and registered in the startup.cs. I'm still grappling on how to intermingle registered services (which I can inject) and new instances of worker classes (which usually hold static information), and passing information between them all.
I'm thinking about how to create a main servlet that the rest of the servlets extends from this. I have some properties that I would like to be accesible for the whole servlets in my app and I want to init them. I think it could be something like this:
public abstract class MainServlet extends HttpServlet {
protected String errorURL = null;
protected String adminMenuURL = null;
protected String AdminLoginServlet = null;
protected String ValidateServlet = null;
// here, more properties and methods...
#Override
public void init() {
errorURL = context.getInitParameter("errorURL");
adminMenuURL = context.getInitParameter("adminMenuURL");
AdminLoginServlet = context.getInitParameter("AdminLoginServlet");
ValidateServlet = context.getInitParameter("ValidatePicsServlet");
// here, some more inits...
}
}
When I create a new Servlet like the following...
public class AdminLoginServlet extends MainServlet {
}
If I forward to AdminLoginServlet, would the parameters (errorURL, adminMenuURL, etc.) be assigned again?
If i override the init method in AdminLoginServlet (and others servlets that extends from MainServlet)... these properties won't be never assigned, isn't it?
How would you do what I pretend to do?
Thanks.
the members adminMenuUrl and so on are assigned when the servlet is first created by the engine, because this is the moment when init() is invoked. Every user request is handled by the same servlet instance, in different threads. When you forward a request to a servlet, the method init() won't be invoked.
you're right, because there can be no instance of MainServlet
I'm not sure how your web app should look like
You should rename the fields AdminLoginServlet and ValidateServlet, because it's bad practice to start fieldnames with upper case letters.
I have a question for the article, which probably many of us have read: Dependency Injection in ASP.NET Web API 2.
Let's assume, that the ProductRepository at some later point in time needs to delegate to some other service. How should ProductRepository request the concrete instance from the dependency injector at that later time as it is a bad practice to inject the dependency injector itself into the ProductRepository?
You can inject the new service inside the ProductRepository just like you injected the IProductRepository into ProductsController.
public class ProductRepository : IDisposable
{
private readonly IOtherService m_OtherService;
public ProductRepository(IOtherService other_service)
{
m_OtherService = other_service;
}
...
}
If you register IOtherService successfully in the container, the container would be able to create ProductRepository and ProductsController successfully.
If it is a problem for you to have the OtherService created everytime (maybe you will not use it all the time), you can use the factory pattern. For example:
public interface IOtherServiceFactory
{
IOtherService Create();
}
public class ProductRepository : IDisposable
{
private readonly IOtherServiceFactory m_OtherServiceFactory;
public ProductRepository(IOtherServiceFactory other_service_factory)
{
m_OtherServiceFactory = other_service_factory;
}
...
}
Now, you can create an instance of OtherService only when you need it.
You have to create an implementation of IOtherServiceFactory and register it with the container.
I have a stateful session bean where a list is maintained:
#Stateful
public class CartDAO{
private List<ShoppingCart> tempCart;
public void add(ShoppingCart shoppingCart){
tempCart.add(shoppingCart);
}
public List<ShoppingCart> getCart(){
return tempCart;
}
#PostConstruct
public void init(){
tempCart = new ArrayList<>();
}
}
Controller1 to add to the cart:
#Named
#SessionScoped
public class Controller1 implements Serializable {
#EJB
CartDAO cartDao;
public String addToShoppingCart() {
cartDao.add(shoppingCart);
}
}
Now, i want to ask you could i get the added items to the list from another cart?
#Named
#SessionScoped
public class Controller2 implements Serializable {
#EJB
CartDAO cartDao;
public String getShoppingCart() {
System.out.println(cartDao.getCart());//returns null
}
}
Obviously the above code returns null.
How do I retrieve the list from another controller. Any help will be much appreciated.
I don't see any obvious mistake here (are you sure that you don't call Controller2#getShoppingCart() before adding any items do your CartDAO?) but here are couple of my notions
you should have your CartDAO implement some interface or make it #LocalBean
all stateful beans should have method annotated with #Remove so you can clean the resources used in the bean (close datasources and son) and bean will be removed from the memory after this call
now it's recommended to use #Inject everywhere instead of #EJB, it's the same (you have to use #EJB only when you inject remote beans)
And also one point, if the System.out.println(cartDao.getCart()); returns null than it means the #PostConstruct haven't been called which is strange. Can you provide some more info about container and your environment?Also show us imports, this is big source of mistakes.