why Spring DefaultLifecycleProcessor use CountDownLatch? - spring

public void stop() {
.....
CountDownLatch latch = new CountDownLatch(this.smartMemberCount);
.....
try {
latch.await(this.timeout, TimeUnit.MILLISECONDS);
.......
}
Stop the specified bean as part of the given set of Lifecycle beans,
making sure that any beans that depends on it are stopped first.
#param lifecycleBeans a Map with bean name as key and Lifecycle instance as value
#param beanName the name of the bean to stop
private void doStop(Map<String, ? extends Lifecycle> lifecycleBeans, final String beanName,
final CountDownLatch latch, final Set<String> countDownBeanNames) {
......
String[] dependentBeans = getBeanFactory().getDependentBeans(beanName);
for (String dependentBean : dependentBeans) {
doStop(lifecycleBeans, dependentBean, latch, countDownBeanNames);
}
......
((SmartLifecycle) bean).stop(() -> {
latch.countDown();
countDownBeanNames.remove(beanName);
......
}
}
This Spring code, when spring find exist dependent Bean, it will run dependent bean before current bean.
I want to konw why spring use countDwonLatch?
I register SmartLifecycle bean exist Dependent Bean like this code.
Because stop2 depends on stop3. When spring close, stop3 run before stop2.If it is a single thread, countDwonLatch is equal to int. In Multi-thread,stop3 run ((SmartLifecycle) bean).stop() before stop2, countDownLatch value is 0 when stop3 not run. So, I think spring will close early,countDownLatch will invalid.
#Component
public class Stop1 implements SmartLifecycle {
.....
#Override
public void stop() {
System.err.println("0");
}
.....
public int getPhase() {
return 1;
}
}
#Component
public class Stop2 implements SmartLifecycle {
....
#Override
public void stop() {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.err.println("2");
}
......
public int getPhase() {
return 1;
}
}
#DependsOn("stop2")
public class Stop3 implements SmartLifecycle {
......
#Override
public void stop() {
System.err.println("3");
}
.....
public int getPhase() {
return 0;
}
}

Related

Class field in Netty ChannelInboundHandler could not autowired

I try to autowire some service class in channelInboundhandler class field.
but when handler use repository field it always null.
Here is my Netty Configuration
my.netty:
server:
bind: 9000
#SpringBootApplication
public class NettyApplication {
public static void main(String[] args) {
SpringApplication.run(NettyApplication.class, args);
}
#Bean
NettyServerConfig serverConfig(#Autowired ServerHandler serverHandler) {
return NettyServerConfig.builder()
.propertiesPrefix("my.netty.server")
.channelInitializer(pipelineOf(loggingChannelHandler(), serverHandler))
.build();
}
#Bean
ChannelHandler loggingChannelHandler() {
return new LoggingHandler(INFO);
}
}
And channelinboundhandler, Service(Repository)
#Slf4j
#Component
#Sharable
public class ServerHandler extends ChannelInboundHandlerAdapter {
#Autowired ServerRepository repository; // always null
#Override
public void channelRead(ChannelHandlerContext ctx, Object object) throws Exception {
log.info("ServerHandler.channelRead()");
String data = repository.findOne();
log.info("data={}", data);
ctx.writeAndFlush(object);
}
}
#Repository
public class ServerRepository {
public String findOne() {
sleep(1000); // data-access time
return "data";
}
private void sleep(int millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Is There any Problem?

Spring Autowired Shared Queue NullPointerException

I'm using Spring for the first time and am trying to implement a shared queue wherein a Kafka listener puts messages on the shared queue, and a ThreadManager that will eventually do something multithreaded with the items it takes off the shared queue. Here is my current implementation:
The Listener:
#Component
public class Listener {
#Autowired
private QueueConfig queueConfig;
private ExecutorService executorService;
private List<Future> futuresThread1 = new ArrayList<>();
public Listener() {
Properties appProps = new AppProperties().get();
this.executorService = Executors.newFixedThreadPool(Integer.parseInt(appProps.getProperty("listenerThreads")));
}
//TODO: how can I pass an approp into this annotation?
#KafkaListener(id = "id0", topics = "bose.cdp.ingest.marge.boseaccount.normalized")
public void listener(ConsumerRecord<?, ?> record) throws InterruptedException, ExecutionException
{
futuresThread1.add(executorService.submit(new Runnable() {
#Override public void run() {
try{
queueConfig.blockingQueue().put(record);
// System.out.println(queueConfig.blockingQueue().take());
} catch (Exception e){
System.out.print(e.toString());
}
}
}));
}
}
The Queue:
#Configuration
public class QueueConfig {
private Properties appProps = new AppProperties().get();
#Bean
public BlockingQueue<ConsumerRecord> blockingQueue() {
return new ArrayBlockingQueue<>(
Integer.parseInt(appProps.getProperty("blockingQueueSize"))
);
}
}
The ThreadManager:
#Component
public class ThreadManager {
#Autowired
private QueueConfig queueConfig;
private int threads;
public ThreadManager() {
Properties appProps = new AppProperties().get();
this.threads = Integer.parseInt(appProps.getProperty("threadManagerThreads"));
}
public void run() throws InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(threads);
try {
while (true){
queueConfig.blockingQueue().take();
}
} catch (Exception e){
System.out.print(e.toString());
executorService.shutdownNow();
executorService.awaitTermination(1, TimeUnit.SECONDS);
}
}
}
Lastly, the main thread where everything is started from:
#SpringBootApplication
public class SourceAccountListenerApp {
public static void main(String[] args) {
SpringApplication.run(SourceAccountListenerApp.class, args);
ThreadManager threadManager = new ThreadManager();
try{
threadManager.run();
} catch (Exception e) {
System.out.println(e.toString());
}
}
}
The problem
I can tell when running this in the debugger that the Listener is adding things to the queue. When the ThreadManager takes off the shared queue, it tells me the queue is null and I get an NPE. It seems like autowiring isn't working to connect the queue the listener is using to the ThreadManager. Any help appreciated.
This is the problem:
ThreadManager threadManager = new ThreadManager();
Since you are creating the instance manually, you cannot use the DI provided by Spring.
One simple solution is implement a CommandLineRunner, that will be executed after the complete SourceAccountListenerApp initialization:
#SpringBootApplication
public class SourceAccountListenerApp {
public static void main(String[] args) {
SpringApplication.run(SourceAccountListenerApp.class, args);
}
// Create the CommandLineRunner Bean and inject ThreadManager
#Bean
CommandLineRunner runner(ThreadManager manager){
return args -> {
manager.run();
};
}
}
You use Spring´s programatic, so called 'JavaConfig', way of setting up Spring beans (classes annotated with #Configuration with methods annotated with #Bean). Usually at application startup Spring will call those #Bean methods under the hood and register them in it's application context (if scope is singleton - the default - this will happen only once!). No need to call those #Bean methods anywhere in your code directly... you must not, otherwise you will get a separate, fresh instance that possibly is not fully configured!
Instead, you need to inject the BlockingQueue<ConsumerRecord> that you 'configured' in your QueueConfig.blockingQueue() method into your ThreadManager. Since the queue seems to be a mandatory dependency for the ThreadManager to work, I'd let Spring inject it via constructor:
#Component
public class ThreadManager {
private int threads;
// add instance var for queue...
private BlockingQueue<ConsumerRecord> blockingQueue;
// you could add #Autowired annotation to BlockingQueue param,
// but I believe it's not mandatory...
public ThreadManager(BlockingQueue<ConsumerRecord> blockingQueue) {
Properties appProps = new AppProperties().get();
this.threads = Integer.parseInt(appProps.getProperty("threadManagerThreads"));
this.blockingQueue = blockingQueue;
}
public void run() throws InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(threads);
try {
while (true){
this.blockingQueue.take();
}
} catch (Exception e){
System.out.print(e.toString());
executorService.shutdownNow();
executorService.awaitTermination(1, TimeUnit.SECONDS);
}
}
}
Just to clarify one more thing: by default the method name of a #Bean method is used by Spring to assign this bean a unique ID (method name == bean id). So your method is called blockingQueue, means your BlockingQueue<ConsumerRecord> instance will also be registered with id blockingQueue in application context. The new constructor parameter is also named blockingQueue and it's type matches BlockingQueue<ConsumerRecord>. Simplified, that's one way Spring looks up and injects/wires dependencies.

Spring 4 - Spring retry 1.2.1.RELEASE #Recover not working

I have created an adapterImpl class that will retry a method with an objA but if it throws an exception(hardcoded to throw) it will call recover method - which will again call the method with objB.
My problem is - The #Recover method is not called. I am not sure what I am doing wrong here.
Spring version - 4.3.5.RELEASE
Spring retry - 1.2.1.RELEASE
My Config class -
#Configuration
#EnableRetry
public class ConfigClass {
#Bean
public ClassTest beanA(){
ClassTest obj = new ClassTest();
obj.setProp(5);
return obj;
}
#Bean
public ClassTest beanB(){
ClassTest obj = new ClassTest();
obj.setProp(10);
return obj;
}
#Bean("adapterImpl")
public AdapterInterfaceImpl adapter(){
AdapterInterfaceImpl obj = new AdapterInterfaceImpl();
return obj;
}
}
My AdapterInterfaceImpl class -
public class AdapterInterfaceImpl implements AdapterInterface{
#Autowired
#Qualifier("beanA")
private ClassTest objA;
#Autowired
#Qualifier("beanB")
private ClassTest objB;
public ClassTest getObjA() {
return objA;
}
public void setObjA(ClassTest objA) {
this.objA = objA;
}
public ClassTest getObjB() {
return objB;
}
public void setObjB(ClassTest objB) {
this.objB = objB;
}
#Retryable(maxAttempts = 3, include = Exception.class, backoff = #Backoff(delay = 2000))
public int getValue(int val) throws Exception{
System.out.println("obj A get Value");
return getValue(objA,val);
}
public int getValue(ClassTest obj, int val) throws Exception{
System.out.println("get Value");
if(obj==objA){
throw new Exception("This is msg");
}
return obj.methodA(val);
}
#Recover
public int getValue(Exception e, int val){
System.out.println("Recover get Value");
try{
return getValue(objB,val);
}catch(Exception e1){
return 0;
}
}
My ClassTest class -
public class ClassTest {
private int prop;
public int getProp() {
return prop;
}
public void setProp(int prop) {
this.prop = prop;
}
public int methodA(int x){
return x+prop;
}
}
My class with main method -
public class App
{
public static void main( String[] args )
{
AbstractApplicationContext context = new
AnnotationConfigApplicationContext(ConfigClass.class);
AdapterInterface adapter = (AdapterInterface)
context.getBean("adapterImpl");
try {
System.out.println(adapter.getValue(3));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
My output is not showing any retry nor recovery -
A get Value
get Value
obj A get Value
get Value
obj A get Value
get Value
org.springframework.retry.ExhaustedRetryException: Cannot locate recovery method; nested exception is java.lang.Exception: This is msg
Spring Retry uses AOP, internal calls (from getValue(int) to getValue(ClassTest, int)) won't go through the proxy.
You have to put the #Retryable on the method that is called externally so that the proxy can intercept the call and apply the retry logic.
There is a similar issue reported in https://github.com/spring-projects/spring-retry/issues/75
So #EnableRetry(proxyTargetClass=true) works as it is now able to find the recovery method in the implementation class.

Spring Boot Custom #Async Wrap Callable

I am working on an application that supports multi tenancy. The tenant's unqiue identifier is stored in a thread local and can be accessed via some service.
To allow parallel processing, I have created a Callable wrapper, sets the thread local variable:
class TenantAwareCallable<T> implements Callable<T> {
private final String tenantName;
private final Callable<T> delegate;
TenantAwareCallable(Callable<T> delegate, String tenantName) {
this.delegate = delegate;
this.tenantName = tenantName;
}
#Override
public T call() throws Exception {
// set threadlocal
TenantContext.setCurrentTenantName(tenantName);
try {
return delegate.call();
} catch (Exception e) {
// log and handle
} finally {
TenantContext.clear();
}
}
}
This can already be used in the application. But what I would like to have is some custom #Async annotation, like for example #TenantAwareAsync or #TenantPreservingAsync, that wraps the callable, created by Spring in this one and then executes it.
Is there some way to get started with this?
Thanks in advance!
I have a working solution for this, so I think sharing it here might help some people some day.
I solved it not by using the TenantAwareCallable but by customizing the Executor service. I chose to extend Spring's ThreadPoolTaskScheduler (since this is what we use in the project).
public class ContextAwareThreadPoolTaskScheduler extends ThreadPoolTaskScheduler {
#Override
protected ScheduledExecutorService createExecutor(int poolSize, ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
return new ContextAwareThreadPoolTaskExecutor(poolSize, threadFactory, rejectedExecutionHandler);
}
}
The actual setting of the context data is done in a customized ScheduledThreadPoolExecutor:
public class ContextAwareThreadPoolTaskExecutor extends ScheduledThreadPoolExecutor {
public ContextAwareThreadPoolTaskExecutor(int poolSize, ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
super(poolSize, threadFactory, rejectedExecutionHandler);
}
#Override
protected <V> RunnableScheduledFuture<V> decorateTask(Callable<V> callable, RunnableScheduledFuture<V> task) {
return new ContextAwareTask<V>(task);
}
#Override
protected <V> RunnableScheduledFuture<V> decorateTask(Runnable runnable, RunnableScheduledFuture<V> task) {
return new ContextAwareTask<V>(task);
}
static private class ContextAwareTask<T> implements RunnableScheduledFuture<T> {
private final RunnableScheduledFuture<T> delegate;
private final TenantContextHolder multitenantContextHolder;
private final LoggingContextHolder loggingContextHolder;
private final SecurityContext securityContext;
ContextAwareTask(RunnableScheduledFuture<T> delegate) {
this.delegate = delegate;
multitenantContextHolder = TenantContextHolder.newInstance();
loggingContextHolder = LoggingContextHolder.newInstance();
securityContext = SecurityContextHolder.getContext();
}
#Override
public void run() {
multitenantContextHolder.apply();
loggingContextHolder.apply();
SecurityContextHolder.setContext(securityContext);
delegate.run();
SecurityContextHolder.clearContext();
loggingContextHolder.clear();
multitenantContextHolder.clear();
}
// all other methods are just delegates
}
}
The Holders are basically just objects to store context state and apply it in the new thread.
public class TenantContextHolder {
private String tenantName;
public static TenantContextHolder newInstance() {
return new TenantContextHolder();
}
private TenantContextHolder() {
this.tenantName = TenantContext.getCurrentTenantName();
}
public void apply() {
TenantContext.setCurrentTenantName(tenantName);
}
public void clear() {
TenantContext.clear();
}
}
The custom implementation of the Scheduler can then be configured in the Spring environment.
#Configuration
public class AsyncConfiguration implements AsyncConfigurer {
private ThreadPoolTaskScheduler taskScheduler;
#Bean
public ThreadPoolTaskScheduler taskScheduler() {
if (taskScheduler == null) {
taskScheduler = new ContextAwareThreadPoolTaskScheduler();
}
return taskScheduler;
}
#Override
public Executor getAsyncExecutor() {
return taskScheduler();
}
}

Get parent bean in prototype bean that gets injected

I would like to have a Bean and a SubBean like this:
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
#Component
public class SubBean implements ApplicationContextAware{
private Object parent;
public void setApplicationContext(ApplicationContext ctx){
this.parent = doSomeMagicToGetMyParent(ctx);
}
public Object getParent(){
return parent;
}
}
#Component
public class SomeBean implements InitializingBean{
#Resource
private SubBean sub;
public void afterPropertiesSet(){
Assert.isTrue(this == sub.getParent());
}
}
The trick I want to achieve is, that the SubBean automagically gets a reference to the Bean it got injected into. Because the scope of the subbean is prototype, it will get injected as a new instance in every parent that wants it to get injected.
My big idea is to exploit this pattern to write a LoggerBean which can be injected into normal beans. The subbean should work just like a SLF4J Logger.
So does anyone know the magic to make this work? :)
EDIT: I've found a solution to do this with a custom BeanPostProcessor:
#Component
public class DependencyInjectionAwareBeanPostProcessor implements BeanPostProcessor {
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean;
}
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
for (Field f : bean.getClass().getFields()) {
if (f.getType().isInstance(IDependencyInjectionAware.class)) {
ReflectionUtils.makeAccessible(f);
try {
IDependencyInjectionAware diAware = (IDependencyInjectionAware) f.get(bean);
diAware.injectedInto(bean);
} catch (IllegalArgumentException e) {
ReflectionUtils.handleReflectionException(e);
} catch (IllegalAccessException e) {
ReflectionUtils.handleReflectionException(e);
}
}
}
return bean;
}
}
Here is the Interface:
public interface IDependencyInjectionAware {
void injectedInto(Object parent);
}
And here a Bean using it:
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
#Component
public class SomeAwareBean implements IDependencyInjectionAware {
private Object parent;
public void injectedInto(Object parent){
this.parent = parent;
}
public Object getParent(){
return parent;
}
}
Here a test with a normal Bean which works perfectly:
#Component
public class UsingBean implements InitializingBean {
#Resource
private SomeAwareBean b;
public void afterPropertiesSet(){
Assert.notNull(b); //works
Assert.isTrue(b.getParent() == this); //works
}
}
Though, when using the same with a normal class which gets the depedencies injected via #Configurable, the test fails:
#Configurable
public class UsingPlainClass implements InitializingBean {
#Resource
private SomeAwareBean b;
public void afterPropertiesSet(){
Assert.notNull(b); //works
Assert.isTrue(b.getParent() == this); //fails because null is returned
}
}
So this seems to have gotten me to another question: Why won't my custom BeanPostProcessor run on a #Configurable classes? Maybe I have to resort to AspectJ afterall...
EDIT: Just to update the status. I did not implement this afterall because this is overengineering...
I find this simpler:
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
#Component
public class SubBean implements ApplicationContextAware{
private Object parent;
public void setApplicationContext(ApplicationContext ctx){
...
}
public Object getParent(){
return parent;
}
//ADDED CODE
public void setParent(Object parent) {
this.parent = parent;
}
//END ADDED CODE
}
#Component
public class SomeBean implements InitializingBean{
private SubBean sub;
//ADDED CODE
#Resource
public void setSub(SubBean sub) {
this.sub = sub;
sub.setParent(this);
}
//END ADDED CODE
public void afterPropertiesSet(){
Assert.isTrue(this == sub.getParent());
}
}
Fixed several bugs with the solution given by the original poster:
import java.lang.reflect.Field;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.util.ReflectionUtils;
public interface DependencyInjectionAware {
void injectedInto(final Object bean, final String beanName);
public static class DependencyInjectionAwareBeanPostProcessor implements
BeanPostProcessor {
private static final Logger logger = Logger.getLogger(DependencyInjectionAwareBeanPostProcessor.class);
#Override
public Object postProcessBeforeInitialization(final Object bean,
final String beanName) {
return bean;
}
#Override
public Object postProcessAfterInitialization(final Object bean,
final String beanName) {
for (final Field f : bean.getClass().getDeclaredFields()) {
logger.info("scanning field " + f.getName() + " of bean " + beanName + " (class= " + bean.getClass() + ")");
if (DependencyInjectionAware.class.isAssignableFrom(f.getType())) {
ReflectionUtils.makeAccessible(f);
try {
final DependencyInjectionAware diAware = (DependencyInjectionAware) f.get(bean);
diAware.injectedInto(bean, beanName);
} catch (final IllegalArgumentException e) {
ReflectionUtils.handleReflectionException(e);
} catch (final IllegalAccessException e) {
ReflectionUtils.handleReflectionException(e);
}
}
}
return bean;
}
}
}

Resources