Start Spring Boot and load properties
@SpringBootApplication(scanBasePackages = {"com.idd.abc.base"})
@EnableRetry
@EnableScheduling
@ConfigurationPropertiesScan({"com.idd.abc.base"})
@PropertySource(ignoreResourceNotFound = true, value = "file:/vault/secrets")
@Slf4j
public class Application {
@SuppressWarnings("squid:S4823")
public static void main(String[] args) {
log.info("### ### ### ABC Spring Boot Base Application starting...");
SpringApplication app =
new SpringApplication(Application.class, AbcMetricsServiceCounterConfiguration.class);
app.setApplicationStartup(new BufferingApplicationStartup(2048));
app.run(args);
}
@Bean
public static PropertySourcesPlaceholderConfigurer placeholderConfigurer() {
PropertySourcesPlaceholderConfigurer propsConfig = new PropertySourcesPlaceholderConfigurer();
propsConfig.setLocation(new ClassPathResource("git.properties"));
propsConfig.setIgnoreResourceNotFound(true);
propsConfig.setIgnoreUnresolvablePlaceholders(true);
return propsConfig;
}
}
Spring Boot Application Statuses
@Component
@RequiredArgsConstructor
@Slf4j
public class AbcApplicationGracefulShutdown
implements ApplicationListener<ContextClosedEvent>, ExitCodeGenerator {
@Override
public void onApplicationEvent(ContextClosedEvent event) {
log.info("@@@ @@@ @@@ ABC Application is closed by event:{}.", event.getSource());
}
@Override
public int getExitCode() {
return 0;
}
}
@Component
@Order(0)
@Slf4j
class AbcApplicationReadyListener implements ApplicationListener<ApplicationReadyEvent> {
@Value("${spring.profiles.active}")
private String activeProfiles;
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
log.info(
"@@@ @@@ @@@ ABC Application is ready and started with profile:{}.", activeProfiles);
}
}
Async Configuraiton
@Configuration
@RequiredArgsConstructor
@EnableAsync
public class AbcAsyncConfigurer implements AsyncConfigurer {
@SuppressWarnings("squid:S3749")
private final AbcAsyncExceptionHandler asyncExceptionHandler;
@Value("${async.handler.concurrency:3}")
private int asyncCorePoolSize;
@Value("${async.queue.capacity:3500}")
private int asyncQueueCapacity;
@Bean
public Executor asyncTaskExecutor() {
final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(asyncCorePoolSize);
executor.setMaxPoolSize(3 * asyncCorePoolSize);
executor.setQueueCapacity(asyncQueueCapacity);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setThreadNamePrefix("AsyncTaskExecutore-");
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.initialize();
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return asyncExceptionHandler;
}
}
@Service
@Slf4j
public class AbcAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
@Override
public void handleUncaughtException(final Throwable t, final Method m, final Object... params) {
log.info("$$$ $$$ $$$ Method name:{}", m.getName());
for (Object param : params) {
log.info("$$$ $$$ $$$ Parameter value:{}", param);
}
if (t instanceof RetryExhaustedException) {
log.error(
AbcAlertMessage.ABC_APP_RETRY_EXHAUSTED
+ " *** *** *** method:"
+ m
+ " failed with recoverable exception and all retries exhausted. Message:"
+ t.getMessage(),
t);
} else if (t instanceof AbcApplicationException) {
log.error(
AbcAlertMessage.ABC_APP_UNRECOVERABLE_FAILURE
+ " *** *** *** method:"
+ m
+ " falied with Un-recoverable Exception. Message:"
+ t.getMessage(),
t);
} else {
log.error(
AbcAlertMessage.ABC_APP_UN_CATEGORIZED_EXCEPTION
+ " *** *** *** method:"
+ m
+ " failed with Un-categoried Exception. Message:"
+ t.getMessage(),
t);
}
}
}
Cache
@Configuration
@EnableCaching
public class AbcCacheManagerConfiguration {
@Bean
@Primary
public CacheManager abcDefaultCacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager("abcDefaultCache");
cacheManager.setCaffeine(
Caffeine.newBuilder()
.initialCapacity(10)
.maximumSize(200)
.expireAfterWrite(1, TimeUnit.MINUTES)
.weakKeys()
.recordStats());
return cacheManager;
}
@Bean
public CacheManager abcSimpleCacheManager() {
return new ConcurrentMapCacheManager("abcSimpleCache");
}
}
@Configuration
@Slf4j
public class AbcBaseConfiguration {
@Bean
public SecureRandom random() {
return new SecureRandom();
}
@Bean
public String hostnameProperty(final Environment env) {
String hostname = env.getProperty("HOSTNAME");
if (null == hostname) {
try {
hostname = InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException e) {
log.warn(
AbcAlertMessage.ABC_APP_INTERNAL_EXCEPTION
+ " ### ### ### Failed to retrieve hostname.",
e);
}
}
return hostname;
}
@Bean
public Clock clock() {
return Clock.system(ZoneId.of("UTC"));
}
@Bean
public InetAddress inetAddress() {
try {
return InetAddress.getLocalHost();
} catch (Exception ex) {
throw new AbcApplicationException(
AbcAlertMessage.ABC_APP_INTERNAL_EXCEPTION
+ " ### ### ### Reading local inet address failed. Message:"
+ ex.getMessage(),
ex);
}
}
@Bean
MeterRegistryCustomizer<MeterRegistry> configurer(
@Value("${spring.application.name}") String applicationName) {
return registry -> registry.config().commonTags("application", applicationName);
}
}
@Configuration
public class AbcMetricsServiceCounterConfiguration {
private static final String CAT = "cat";
private static final String SERVICE = "service";
@Bean
public Counter userErrorCounter(MeterRegistry meterRegistry) {
return meterRegistry.counter("user.id.error", CAT, SERVICE);
}
@Bean
public Counter userAccessCounter(MeterRegistry meterRegistry) {
return meterRegistry.counter("user.id.access", CAT, SERVICE);
}
}
@Configuration
public class TimedAspectConfiguration {
@Bean
public TimedAspect timedAspect(MeterRegistry meterRegistry) {
return new TimedAspect(meterRegistry);
}
}
===================================================================
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Service
@Validated
public @interface ValidatedService {}
Condition
public class SolaceCondition extends AnyNestedCondition {
SolaceCondition() {
super(ConfigurationPhase.PARSE_CONFIGURATION);
}
@ConditionalOnProperty(
value = "solace.jms.direct.enabled",
havingValue = "true",
matchIfMissing = false)
static class JmsDirectCondition {}
@ConditionalOnProperty(
value = "solace.jms.spring.enabled",
havingValue = "true",
matchIfMissing = false)
static class JmsSpringCondition {}
}
public class OnUnixCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return SystemUtils.IS_OS_LINUX;
}
}
Usage Demo
@ValidatedService
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {
@SuppressWarnings("squid:S3749")
private final SecureRandom random;
@SuppressWarnings("squid:S3749")
@Qualifier("userAccessCounter")
private final Counter accessCouter;
private SoftReference<Map<Long, User>> userMapRef = new SoftReference<>(new HashMap<>());
@Timed(
extraTags = {"cat", "service"},
percentiles = {0.50, 0.95, 0.99},
histogram = false)
@Log4jDiagnosticContextEnable
@Override
public String getAccount(@NotNull final User user) {
accessCouter.increment();
return user.getId() + "-" + random.nextInt(100000000);
}
/*
* Example of asynchronous execution
*/
@Async("asyncTaskExecutor")
@Timed(
extraTags = {"cat", "service"},
percentiles = {0.50, 0.95, 0.99},
histogram = false)
@Log4jDiagnosticContextEnable
@Override
public ListenableFuture<String> getIdAndName(@NotNull final User user) {
accessCouter.increment();
return new AsyncResult<>(user.getId() + "-" + user.getName());
}
/*
* Example of handling AsyncUncaughtExceptionHandler
*/
@Async("asyncTaskExecutor")
@Timed(
extraTags = {"cat", "service"},
percentiles = {0.50, 0.95, 0.99},
histogram = false)
@Log4jDiagnosticContextEnable
@Override
public void asyncFailure(final User user) {
accessCouter.increment();
throw new RuntimeException("TEST EXCEPTION");
}
@Timed(
extraTags = {"cat", "service"},
percentiles = {0.50, 0.95, 0.99},
histogram = false)
@Log4jDiagnosticContextEnable
@Override
public synchronized User getUser(long id) {
Map<Long, User> userMap = this.getUserMap();
User user = userMap.get(id);
if (user == null) {
user = createUser(id);
}
return user;
}
@Timed(
extraTags = {"cat", "service"},
percentiles = {0.50, 0.95, 0.99},
histogram = false)
@Log4jDiagnosticContextEnable
@Override
public synchronized User updateUser(long id) {
Map<Long, User> userMap = this.getUserMap();
User user = userMap.get(id);
if (user == null) {
user = createUser(id);
} else {
user.setName(String.valueOf(random.nextInt(100)));
}
return user;
}
private Map<Long, User> getUserMap() {
Map<Long, User> userMap = this.userMapRef.get();
if (userMap == null) {
this.userMapRef = new SoftReference<>(new ConcurrentHashMap<>());
}
return userMapRef.get();
}
private User createUser(long id) {
User user;
user = new User();
user.setId(id);
user.setName(String.valueOf(random.nextInt(100)));
return user;
}
}
No comments:
Post a Comment