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
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"