Why does CachePut not work in this example? - spring-boot

I am playing around with the Spring framework and I would like to get my name returned from the cache. After 5 seconds I will update the cache and I hope to receive a new name.... unfortunately this is not working.... why?
#Component
public class Test {
public String name = "peter";
#Cacheable(value = "numCache")
public String getName() {
return name;
}
#Scheduled(fixedRate = 5000)
#CachePut(value = "numCache")
public String setName() {
this.name = "piet";
return name;
}
}
#Component
public class AppRunner implements CommandLineRunner {
public void run(String... args) throws Exception {
Test test = new Test();
while(true) {
Thread.sleep(1000);
System.out.println(test.getName());
}
}
}
#SpringBootApplication
#EnableCaching
#EnableScheduling
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

You are creating an instance of Test yourself with new, you are not autowiring it. I would try like this:
#Component
public class Test {
public String name = "peter";
#Cacheable(value = "numCache")
public String getName() {
return name;
}
#Scheduled(fixedRate = 5000)
#CachePut(value = "numCache")
public String setName() {
this.name = "piet";
return name;
}
}
#Component
public class AppRunner implements CommandLineRunner {
#Autowired private Test test;
public void run(String... args) throws Exception {
while(true) {
Thread.sleep(1000);
System.out.println(test.getName());
}
}
}

Related

Wrong profile is active

#SpringBootApplication
public class SfgDiApplication {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(SfgDiApplication.class, args);
PetController petController = ctx.getBean("petController", PetController.class);
System.out.println("--- The Best Pet is ---");
System.out.println(petController.whichPetIsTheBest());
}
#Controller
#ResponseBody
public class PetController {
public PetController(PetService petService) {
this.petService = petService;
}
private final PetService petService;
#GetMapping("pet-type")
public String whichPetIsTheBest(){
return petService.getPetType();
}
}
public interface PetService {
String getPetType();
}
#Service("cat")
public class CatPetService implements PetService {
#Override
public String getPetType() {
return "Cats Are the Best!";
}
}
#Profile({"dog", "default"})
public class DogPetService implements PetService {
public String getPetType(){
return "Dogs are the best!";
}
}
application.properties
spring.profiles.active=dog
Result
--- The Best Pet is ---
Cats Are the Best!
I don't understand why cats are here. I can even comment the properties out, but cats are still here. I would like to see dogs.
What can I try next?
It looks like the DogService is not a bean. So in the end you only have a single bean (CatService) and this one will be picked all the time.
You should define a bean of DogPetService with #service.
You should add the cat profile to CatPetService.
Like this :
#Service("cat")
#Profile({"cat"})
public class CatPetService implements PetService {
#Override
public String getPetType() {
return "Cats Are the Best!";
}
}
#Profile({"dog", "default"})
#Service("dog")
public class DogPetService implements PetService {
public String getPetType(){
return "Dogs are the best!";
}
}
I think you can achieve what you want like this:
#Configuration("petConfig")
#RequiredArgsConstructor(onConstructor = #__(#Autowired))
public class PetConfig {
#Value("${spring.profiles.active}")
private String type;
#Bean(name = "petService")
#Primary
public PetService petService() {
PetService petService = null;
if ("cat".equals(type)) {
petService = new CatPetService();
}
if ("dog".equals(type)) {
petService = new DogPetService();
}
return petService;
}
}
Annotate both CatPetService and DogPetService with #Service. This way you can easily adapt the code without hardcodings and duplication.

unable to bind list of object properties from application.yml in spring

I want to bind a list of object properties to a field in spring bean, but spring does not bind it. What am I missing? My env is SpringBoot v2.7.1 + Java 8.
application.yml
application:
mappings:
- oldname: 'old name 1'
newname: 'new name 1'
- oldname: 'old name 2'
newname: 'new name 2'
MappingProperties.java
#ConfigurationProperties(prefix = "application")
public class MappingProperties {
private List<Mapping> mappings;
public List<Mapping> getServers() {
return mappings;
}
public void setServers(List<Mapping> mappings) {
this.mappings = mappings;
}
public class Mapping {
private String oldname;
private String newname;
public String getOldname() {
return oldname;
}
public void setOldname(String oldname) {
this.oldname = oldname;
}
public String getNewname() {
return newname;
}
public void setNewname(String newname) {
this.newname = newname;
}
}
}
DemoApplication.java
#EnableConfigurationProperties(MappingProperties.class)
#SpringBootApplication
public class DemoApplication implements CommandLineRunner {
#Autowired
private MappingProperties mappingProperties;
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
#Override
public void run(String... args) throws Exception {
System.out.println(mappingProperties);
}
}
Looks like you are missing #ConfigurationPropertiesScan
https://www.baeldung.com/configuration-properties-in-spring-boot
UPD: an implementation example was found here: https://www.baeldung.com/spring-boot-yaml-list

How to use Spring boot AutoWired and ScheduledExecutorService?

I need to use autowired in more than one class with ScheduledExecutorService, what I have tried is shown in this code. logging size of User list in below example always shows 0, even after user added to arraylist. How to properly use Autowired and ScheduledExecutorService in spring boot?
#Component
public class AnotherClass {
List<User> users = new ArrayList();
public void addUser(User user){
users.add(user);
}
public void logUsers(){
logger.info("User size " + users.size()); <================= Always logs 0, when called from executor
}
}
#RestController
public class SecondClass {
#Autowired
private AnotherClass anotherClass;
#GetMapping(value="/user/test")
public void logUsers(){
anotherClass.addUser(new User());
}
}
Application Class
#Component
#SpringBootApplication
public class SpringBootDemoApplication {
private ScheduledExecutorService exec = Executors.newScheduledThreadPool(1);
#Autowired
private AnotherClass anotherClass;
#PostConstruct
public void init() {
logger();
}
public static void main(String[] args) {
SpringApplication.run(SpringBootDemoApplication.class, args);
}
public void logger(){
exec.scheduleAtFixedRate(new Runnable(){
#Override
public void run(){
try {
anotherClass.logUsers();
}catch (Exception e){
}
}
}, 2000, 1000, TimeUnit.MILLISECONDS);
}
}
The code works if you use the Spring #Autowired and not the #AutoWired Annotation.

Spring boot check external service status on boot

I want check some external http service before my Spring Boot is ready.
The url to the external web service are stored in a property file with a #ConfigurationProperties class.
How do this check i tried using a springApplication.addListner() with a ping method. But the property class have not then been initialized.
public class ApplicationStartListener implements ApplicationListener<ApplicationPreparedEvent> {
#Override
public void onApplicationEvent(ApplicationPreparedEvent event) {
String url = AppProp.getURL();
inet = InetAddress.getByName(url );
inet.isReachable(5000)
...
application.yml
tops:
http://service.com
#Component
#ConfigurationProperties("tops")
public class AppProp{
private static String url;
public static String getUrl() {
The easiest way to accomplish this is to implement the ApplicationRunner interface.
From the Spring Boot documentation [1]
If you need to run some specific code once the SpringApplication has started, you can implement the ApplicationRunner or CommandLineRunner interfaces. Both interfaces work in the same way and offer a single run method which will be called just before SpringApplication.run(…​) completes.
[1] https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-spring-application.html#boot-features-command-line-runner
Assuming you have url defined in application.properties:
#SpringBootApplication
public class MyApplication implements ApplicationRunner
{
#Inject
private AppConfig appConfig;
#Inject
private ConfigurableApplicationContext applicationContext;
public static void main(String[] args)
{
SpringApplication.run(MyApplication.class, args);
}
#Override
public void run(ApplicationArguments args) throws Exception
{
InetAddress inetAddress = InetAddress.getByName(appConfig.getUrl());
if (!inetAddress.isReachable(5000))
{
// Stop the application or do other things
}
}
#Component
#ConfigurationProperties
public static class AppConfig
{
private String url;
public String getUrl()
{
return url;
}
public void setUrl(String url)
{
this.url = url;
}
}
}
If you need even more control than this, you can use SpringApplicationRunListener [2]
[2] http://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/SpringApplicationRunListener.html
#SpringBootApplication
public class MyApplication implements SpringApplicationRunListener
{
public MyApplication() { }
public MyApplication(SpringApplication springApplication, String[] args) { }
public static void main(String[] args)
{
SpringApplication.run(MyApplication.class, args);
}
#Override
public void started() { }
#Override
public void environmentPrepared(ConfigurableEnvironment environment)
{
// 1st opportunity
InetAddress inetAddress = InetAddress.getByName(environment.getProperty("url"));
if (!inetAddress.isReachable(5000))
{
// Stop the application or do other things
}
}
#Override
public void contextPrepared(ConfigurableApplicationContext context)
{
// 2nd opportunity
InetAddress inetAddress = InetAddress.getByName(context.getEnvironment().getProperty("url"));
if (!inetAddress.isReachable(5000))
{
// Stop the application or do other things
}
}
#Override
public void contextLoaded(ConfigurableApplicationContext context)
{
// 3rd opportunity
InetAddress inetAddress = InetAddress.getByName(context.getEnvironment().getProperty("url"));
if (!inetAddress.isReachable(5000))
{
// Stop the application or do other things
}
}
#Override
public void finished(ConfigurableApplicationContext context, Throwable exception)
{
// 4th opportunity
InetAddress inetAddress = InetAddress.getByName(context.getEnvironment().getProperty("url"));
if (!inetAddress.isReachable(5000))
{
// Stop the application or do other things
}
}
#Component
#ConfigurationProperties
public static class AppConfig {
private String url;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
}
then create META-INF\spring.factories and add
org.springframework.boot.SpringApplicationRunListener=com.foobar.MyApplication

Why i get java.lang.IllegalArgumentException: error at ::0 can't find referenced pointcut getLogging

I get this exception on the title. I give some code following:
#Component("student")
public class Student {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void printSomething() {
// get logging with aop
System.out.println("student printed something");
// get logging with aop
}
}
#Aspect
#Component
public class StudentLogging {
private final static Logger logger = Logger.getLogger(StudentLogging.class.getName());
#Pointcut("execution(* aspectorientedprog.aopexample.Student.printSomething(..))")
private void getLogging() {
}
#Around("getLogging()")
public String aroundPrintSomething(ProceedingJoinPoint joinPoint) throws Throwable {
logger.info("before printing something");
Object o = joinPoint.proceed();
logger.info("after printing something");
return o.toString();
}
}
public class AspectStudentTest {
#Test
public void aspect_student_test() {
ApplicationContext context = new ClassPathXmlApplicationContext("aspect/aspect-conf.xml");
Student student = context.getBean("student", Student.class);
student.printSomething();
System.out.println();
}
}
my configuration file:
<context:annotation-config/>
<context:component-scan base-package="aspectorientedprog"/>
<aop:aspectj-autoproxy/>
I research something about this error, but all solutions are not worked, it was about AOP version. if i use only
#Around(execution("class"))
it is working truly but if i use the #Pointcut and #Around like above i got this problem...
thanks for your answers
Try with:
#Pointcut("execution(* aspectorientedprog.aopexample.Student.printSomething(..))")
public void getLogging() {
}

Resources