Section 9 Flashcards
Create a example where singleton or prototype is used in a class and compare the differences. Use annotations
//TennisCoach class using prototype scope @Component @Scope("prototype") public class TennisCoach implements Coach {
@Autowired @Qualifier("gymFortuneService") private FortuneService fortuneService;
public TennisCoach() { }
@Override public String getDailyWorkout() { return "Daily workout method"; } @Override public String getDailyFortune() { return fortuneService.getFortune(); }
}
//Main class where the result is displayed public class Main {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("file:src/main/java/com/springboot/annotations/applicationContext.xml");
Coach theCoach = context.getBean("tennisCoach", Coach.class); Coach alphaCoach = context.getBean("tennisCoach", Coach.class); boolean result = (theCoach == alphaCoach); System.out.println(result); context.close(); }
}
What you know about return values of @PostConstruct and @PreDestroy methods ?
Most commonly used in methods with this 2 annotations is void because you cannot capture the return value
Which is the difference between a parameter and an argument? Please explain with an example
//color is a parameter public void getColor( String color ){ System.out.println("The color is": + color); }
//Purple is an argument public static void main(String[] args) { getColor("Purple"); }
Methods marked with @PostConstruct or @PreDestroy annotations can have arguments ?
No! this kind of methods could not accept arguments!
When @PostConstruct method will execute ? But @PreDestroy ?
@PostConstruct method will execute imediatelly after default contructor initialization.
@PreDestroy will be the last method executed before program will finish the execution.
Using TennisCoach class and needed annotations, create the upcomming output:
TennisCoach default constructor should appear before doMyStartupStaff method TennisCoach: inside of doMyStartupStuff Daily workout method Lucky TennisCoach: inside of doMyCleanupSuff
//Inside TennisCoach class @Component public class TennisCoach implements Coach {
@Autowired @Qualifier("gymFortuneService") private FortuneService fortuneService;
public TennisCoach() { System.out.println("TennisCoach constructor should appear before doMyStartupStaff method"); }
@Override public String getDailyWorkout() { return "Daily workout method"; } @Override public String getDailyFortune() { return fortuneService.getFortune(); }
//define my init method @PostConstruct public void doMyStartupStuff() { System.out.println("TennisCoach: inside of doMyStartupStuff"); }
//define my destroy method @PreDestroy public void doMyCleanupSuff() { System.out.println("TennisCoach: inside of doMyCleanupSuff");
}
//Main class public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("file:src/main/java/com/springboot/annotations/applicationContext.xml");
Coach theCoach = context.getBean("tennisCoach", Coach.class); System.out.println(theCoach.getDailyWorkout()); System.out.println(theCoach.getDailyFortune()); context.close(); }
When the @PreDestroy method is not executed ?
When using Scope(“prototype”)
What can we do so the @PreDestroy method to be executed when using prototype scope ?
//A custom bean processor must be created @Component public class MyCustomBeanProcessor implements BeanPostProcessor, BeanFactoryAware, DisposableBean {
private BeanFactory beanFactory; private final List prototypeBeans = new LinkedList<>(); @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// after start up, keep track of the prototype scoped beans. // we will need to know who they are for later destruction
if (beanFactory.isPrototype(beanName)) { synchronized (prototypeBeans) { prototypeBeans.add(bean); } }
return bean; } @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { this.beanFactory = beanFactory; } @Override public void destroy() throws Exception { // loop through the prototype beans and call the destroy() method on each one synchronized (prototypeBeans) { for (Object bean : prototypeBeans) { if (bean instanceof DisposableBean) { DisposableBean disposable = (DisposableBean)bean; try { disposable.destroy(); } catch (Exception e) { e.printStackTrace(); } } } prototypeBeans.clear(); } } }
//TennisCoach must implement DisposasbleBean interface also @Component @Scope("prototype") public class TennisCoach implements Coach, DisposableBean {
@Autowired @Qualifier("gymFortuneService") private FortuneService fortuneService;
public TennisCoach() { System.out.println("TennisCoach constructor should appear before doMyStartupStaff method"); }
@Override public String getDailyWorkout() { return "Daily workout method"; } @Override public String getDailyFortune() { return fortuneService.getFortune(); }
//define my init method @PostConstruct public void doMyStartupStuff() { System.out.println("TennisCoach: inside of doMyStartupStuff"); }
//define my destroy method @PreDestroy public void doMyCleanupSuff() { System.out.println("TennisCoach: inside of doMyCleanupSuff");
} @Override public void destroy() throws Exception { System.out.println(">> TennisCoach: inside destroy()"); }
Practice Activity #6 - Bean Scopes with Annotations
- Modify your file based fortune service to make use of the @PostConstruct annotation
- In the @PostConstruct code, read the fortunes from a text file (.txt).
- Test your application and verify your @PostConstruct code is being executed. Hint, add some println statements.
Output:
> > FileFortuneService: inside default constructor
Oct 11, 2021 7:02:35 PM org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor lambda$buildAutowiringMetadata$2
INFO: Autowired annotation should only be used on methods with parameters: public void com.mycompany.springdemo.FileFortuneService.loadTheFortunesFile()
FileFortuneService: inside method loadTheFortunesFile
Reading fortunes from file: C:\foodbar\fortune-data.txt
File exists: true
PingPongCoach: inside default constructor
Practice your pingpong drop shot
Never give up.
//PingPongCoach @Component public class PingPongCoach implements Coach {
@Autowired @Qualifier("fileFortuneService") private FortuneService fortuneService;
public PingPongCoach() { System.out.println(">> PingPongCoach: inside default constructor"); }
@Override public String getDailyWorkout() { return "Practice your pingpong drop shot"; } @Override public String getDailyFortune() { return fortuneService.getDailyFortune(); }
}
//FileFortuneService @Component public class FileFortuneService implements FortuneService {
String file = "C:\\foodbar\\fortune-data.txt"; ArrayList fileItems;
public FileFortuneService() { System.out.println(">> FileFortuneService: inside default constructor"); }
@Autowired public void loadTheFortunesFile() { System.out.println(">> FileFortuneService: inside method loadTheFortunesFile"); System.out.println("Reading fortunes from file: C:\\foodbar\\fortune-data.txt"); fileItems = new ArrayList<>(); if (!file.toString().equals("")) { System.out.println("File exists: true"); try (BufferedReader br = new BufferedReader(new FileReader(file))) { String line; while ((line = br.readLine()) != null) { fileItems.add(line); }
} catch (IOException e) { e.printStackTrace(); } } }
@Override public String getDailyFortune() { int randomNum = new Random().nextInt(fileItems.size());
return fileItems.get(randomNum); }
}
//Main public class Main {
public static void main(String[] args) { ClassPathXmlApplicationContext container = new ClassPathXmlApplicationContext("file:src/main/java/com/mycompany/springdemo/applicationContext.xml"); Coach coach = container.getBean("pingPongCoach", Coach.class); System.out.println(coach.getDailyWorkout()); System.out.println(coach.getDailyFortune()); container.close(); }
}
//applicationContext.xml context:component-scan base-package="com.mycompany.springdemo"