JAVA-19555 Move articles from spring-core-5 module to spring-boot-annotations-2 module (#13711)

* JAVA-19555 Move articles from spring-core-5 module to spring-boot-annotations-2 module

* JAVA-19555 Move articles from spring-core module to spring-boot-annotations-2 module
This commit is contained in:
anuragkumawat
2023-03-26 23:55:47 +05:30
committed by GitHub
parent eec8618a3d
commit c1f768e162
39 changed files with 9 additions and 4 deletions

View File

@@ -7,4 +7,8 @@ This module contains articles about Spring Boot annotations
- [Spring Conditional Annotations](https://www.baeldung.com/spring-conditional-annotations)
- [Guide to @SpringBootConfiguration in Spring Boot](https://www.baeldung.com/springbootconfiguration-annotation)
- [Spring @Primary Annotation](http://www.baeldung.com/spring-primary)
- [Spring Bean Names](https://www.baeldung.com/spring-bean-names)
- [AliasFor Annotation in Spring](https://www.baeldung.com/spring-aliasfor-annotation)
- [A Quick Guide to the Spring @Lazy Annotation](https://www.baeldung.com/spring-lazy-annotation)
- [Instantiating Multiple Beans of the Same Class with Spring Annotations](https://www.baeldung.com/spring-same-class-multiple-beans)
- More articles: [[<-- prev]](/spring-boot-modules/spring-boot-annotations)

View File

@@ -28,6 +28,11 @@
<artifactId>mockito-inline</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,29 @@
package com.baeldung.aliasfor;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@RequestMapping
public @interface MyMapping {
@AliasFor(annotation = RequestMapping.class, attribute = "method")
RequestMethod[] action() default {};
@AliasFor(annotation = RequestMapping.class, attribute = "path")
String[] value() default {};
@AliasFor(annotation = RequestMapping.class, attribute = "path")
String[] mapping() default {};
@AliasFor(annotation = RequestMapping.class, attribute = "path")
String[] route() default {};
}

View File

@@ -0,0 +1,13 @@
package com.baeldung.aliasfor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class MyMappingController {
@MyMapping(action = RequestMethod.PATCH, route = "/test")
public void mappingMethod() {
}
}

View File

@@ -0,0 +1,23 @@
package com.baeldung.lazy;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
@Lazy
@Configuration
@ComponentScan(basePackages = "com.baeldung.lazy")
public class AppConfig {
@Lazy
@Bean
public Region getRegion(){
return new Region();
}
@Bean
public Country getCountry(){
return new Country();
}
}

View File

@@ -0,0 +1,13 @@
package com.baeldung.lazy;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
@Lazy
@Component
public class City {
public City() {
System.out.println("City bean initialized");
}
}

View File

@@ -0,0 +1,8 @@
package com.baeldung.lazy;
public class Country {
public Country() {
System.out.println("Country bean initialized");
}
}

View File

@@ -0,0 +1,19 @@
package com.baeldung.lazy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
public class Region {
@Lazy
@Autowired
private City city;
public Region() {
System.out.println("Region bean initialized");
}
public City getCityInstance() {
return city;
}
}

View File

@@ -0,0 +1,17 @@
package com.baeldung.multibeaninstantiation.solution1;
public class Person {
private String firstName;
private String lastName;
public Person(String firstName, String secondName) {
super();
this.firstName = firstName;
this.lastName = secondName;
}
@Override
public String toString() {
return "Person [firstName=" + firstName + ", secondName=" + lastName + "]";
}
}

View File

@@ -0,0 +1,17 @@
package com.baeldung.multibeaninstantiation.solution1;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class PersonConfig {
@Bean
public Person personOne() {
return new Person("Harold", "Finch");
}
@Bean
public Person personTwo() {
return new Person("John", "Reese");
}
}

View File

@@ -0,0 +1,11 @@
package com.baeldung.multibeaninstantiation.solution1;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringApp1 {
public static void main(String[] args) {
SpringApplication.run(SpringApp1.class, args);
}
}

View File

@@ -0,0 +1,17 @@
package com.baeldung.multibeaninstantiation.solution2;
public class Person {
private String firstName;
private String lastName;
public Person(String firstName, String secondName) {
super();
this.firstName = firstName;
this.lastName = secondName;
}
@Override
public String toString() {
return "Person [firstName=" + firstName + ", secondName=" + lastName + "]";
}
}

View File

@@ -0,0 +1,10 @@
package com.baeldung.multibeaninstantiation.solution2;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan("com.baeldung.multibeaninstantiation.solution2")
public class PersonConfig {
}

View File

@@ -0,0 +1,13 @@
package com.baeldung.multibeaninstantiation.solution2;
import org.springframework.stereotype.Component;
import com.baeldung.multibeaninstantiation.solution2.Person;
@Component
public class PersonOne extends Person {
public PersonOne() {
super("Harold", "Finch");
}
}

View File

@@ -0,0 +1,13 @@
package com.baeldung.multibeaninstantiation.solution2;
import org.springframework.stereotype.Component;
import com.baeldung.multibeaninstantiation.solution2.Person;
@Component
public class PersonTwo extends Person {
public PersonTwo() {
super("John", "Reese");
}
}

View File

@@ -0,0 +1,11 @@
package com.baeldung.multibeaninstantiation.solution2;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringApp2 {
public static void main(String[] args) {
SpringApplication.run(SpringApp2.class, args);
}
}

View File

@@ -0,0 +1,33 @@
package com.baeldung.multibeaninstantiation.solution3;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
public class Human implements InitializingBean {
private Person personOne;
private Person personTwo;
@Override
public void afterPropertiesSet() throws Exception {
Assert.notNull(personOne, "Harold is alive!");
Assert.notNull(personTwo, "John is alive!");
}
/* Setter injection */
@Autowired
public void setPersonOne(Person personOne) {
this.personOne = personOne;
this.personOne.setFirstName("Harold");
this.personOne.setSecondName("Finch");
}
@Autowired
public void setPersonTwo(Person personTwo) {
this.personTwo = personTwo;
this.personTwo.setFirstName("John");
this.personTwo.setSecondName("Reese");
}
}

View File

@@ -0,0 +1,9 @@
package com.baeldung.multibeaninstantiation.solution3;
import java.util.List;
public interface MultiBeanFactory<T> {
List<T> getObject(String name) throws Exception;
Class<?> getObjectType();
}

View File

@@ -0,0 +1,49 @@
package com.baeldung.multibeaninstantiation.solution3;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Qualifier;
@Qualifier(value = "personOne, personTwo")
public class Person implements FactoryBean<Object> {
private String firstName;
private String secondName;
public Person() {
// initialization code (optional)
}
@Override
public Class<Person> getObjectType() {
return Person.class;
}
@Override
public Object getObject() throws Exception {
return new Person();
}
public boolean isSingleton() {
return true;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getSecondName() {
return secondName;
}
public void setSecondName(String secondName) {
this.secondName = secondName;
}
@Override
public String toString() {
return "Person [firstName=" + firstName + ", secondName=" + secondName + "]";
}
}

View File

@@ -0,0 +1,22 @@
package com.baeldung.multibeaninstantiation.solution3;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class PersonConfig {
@Bean
public PersonFactoryPostProcessor PersonFactoryPostProcessor() {
return new PersonFactoryPostProcessor();
}
@Bean
public Person person() {
return new Person();
}
@Bean
public Human human() {
return new Human();
}
}

View File

@@ -0,0 +1,33 @@
package com.baeldung.multibeaninstantiation.solution3;
import java.util.Map;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
public class PersonFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
Map<String, Object> map = beanFactory.getBeansWithAnnotation(Qualifier.class);
for (Map.Entry<String, Object> entry : map.entrySet()) {
createInstances(beanFactory, entry.getKey(), entry.getValue());
}
}
private void createInstances(ConfigurableListableBeanFactory beanFactory, String beanName, Object bean) {
Qualifier qualifier = bean.getClass()
.getAnnotation(Qualifier.class);
for (String name : extractNames(qualifier)) {
Object newBean = beanFactory.getBean(beanName);
beanFactory.registerSingleton(name.trim(), newBean);
}
}
private String[] extractNames(Qualifier qualifier) {
return qualifier.value()
.split(",");
}
}

View File

@@ -0,0 +1,11 @@
package com.baeldung.multibeaninstantiation.solution3;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringApp3 {
public static void main(String[] args) {
SpringApplication.run(SpringApp3.class, args);
}
}

View File

@@ -0,0 +1,5 @@
package com.baeldung.springbean.naming.component;
public interface Animal {
String name();
}

View File

@@ -0,0 +1,14 @@
package com.baeldung.springbean.naming.component;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
@Component
@Qualifier("cat")
public class Cat implements Animal {
@Override
public String name() {
return "Cat";
}
}

View File

@@ -0,0 +1,7 @@
package com.baeldung.springbean.naming.component;
import org.springframework.stereotype.Component;
@Component("myBean")
public class CustomComponent {
}

View File

@@ -0,0 +1,13 @@
package com.baeldung.springbean.naming.component;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
@Component
@Qualifier("dog")
public class Dog implements Animal {
@Override
public String name() {
return "Dog";
}
}

View File

@@ -0,0 +1,14 @@
package com.baeldung.springbean.naming.configuration;
import com.baeldung.springbean.naming.service.AuditService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AuditConfiguration {
@Bean
public AuditService audit() {
return new AuditService();
}
}

View File

@@ -0,0 +1,19 @@
package com.baeldung.springbean.naming.configuration;
import com.baeldung.springbean.naming.component.CustomComponent;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration("configuration")
public class MyConfiguration {
@Bean("qualifierComponent")
public CustomComponent component() {
return new CustomComponent();
}
@Bean("beanComponent")
public CustomComponent myComponent() {
return new CustomComponent();
}
}

View File

@@ -0,0 +1,12 @@
package com.baeldung.springbean.naming.controller;
import com.baeldung.springbean.naming.service.MessagingService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class MessagingController {
@Autowired
private MessagingService service;
}

View File

@@ -0,0 +1,4 @@
package com.baeldung.springbean.naming.service;
public class AuditService {
}

View File

@@ -0,0 +1,7 @@
package com.baeldung.springbean.naming.service;
import org.springframework.stereotype.Service;
@Service
public class LoggingService {
}

View File

@@ -0,0 +1,4 @@
package com.baeldung.springbean.naming.service;
public interface MessagingService {
}

View File

@@ -0,0 +1,14 @@
package com.baeldung.springbean.naming.service;
import com.baeldung.springbean.naming.component.CustomComponent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
@Service
public class MessagingServiceImpl implements MessagingService {
@Autowired
@Qualifier("qualifierComponent")
private CustomComponent customComponent;
}

View File

@@ -0,0 +1,26 @@
package com.baeldung.springbean.naming.service;
import com.baeldung.springbean.naming.component.Animal;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
@Service
public class PetShow {
@Autowired
@Qualifier("dog")
private Animal dog;
@Autowired
@Qualifier("cat")
private Animal cat;
public Animal getDog() {
return dog;
}
public Animal getCat() {
return cat;
}
}

View File

@@ -0,0 +1,61 @@
package com.baeldung.aliasfor;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.lang.reflect.Method;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = MyMappingController.class)
public class AliasForUnitTest {
@Autowired
private ConfigurableApplicationContext context;
Class controllerClass;
@Before
public void setControllerBean() {
MyMappingController controllerBean = context.getBean(MyMappingController.class);
controllerClass = controllerBean.getClass();
}
@Test
public void givenComposedAnnotation_whenExplicitAlias_thenMetaAnnotationAttributeOverridden() {
for (Method method : controllerClass.getMethods()) {
if (method.isAnnotationPresent(MyMapping.class)) {
MyMapping annotation = AnnotationUtils.findAnnotation(method, MyMapping.class);
RequestMapping metaAnnotation = AnnotationUtils.findAnnotation(method, RequestMapping.class);
assertEquals(RequestMethod.PATCH, annotation.action()[0]);
assertEquals(0, metaAnnotation.method().length);
}
}
}
@Test
public void givenComposedAnnotation_whenImplictAlias_thenAttributesEqual() {
for (Method method : controllerClass.getMethods()) {
if (method.isAnnotationPresent(MyMapping.class)) {
MyMapping annotationOnBean = AnnotationUtils.findAnnotation(method, MyMapping.class);
assertEquals(annotationOnBean.mapping()[0], annotationOnBean.route()[0]);
assertEquals(annotationOnBean.value()[0], annotationOnBean.route()[0]);
}
}
}
}

View File

@@ -0,0 +1,34 @@
package com.baeldung.lazy;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class LazyAnnotationUnitTest {
@Test
public void givenLazyAnnotation_whenConfigClass_thenLazyAll() {
// Add @Lazy to AppConfig.class while testing
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(AppConfig.class);
ctx.refresh();
ctx.getBean(Region.class);
ctx.getBean(Country.class);
}
@Test
public void givenLazyAnnotation_whenAutowire_thenLazyBean() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(AppConfig.class);
ctx.refresh();
Region region = ctx.getBean(Region.class);
region.getCityInstance();
}
@Test
public void givenLazyAnnotation_whenBeanConfig_thenLazyBean() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(AppConfig.class);
ctx.refresh();
ctx.getBean(Region.class);
}
}

View File

@@ -0,0 +1,65 @@
package com.baeldung.springbean.naming;
import com.baeldung.springbean.naming.component.Cat;
import com.baeldung.springbean.naming.component.Dog;
import com.baeldung.springbean.naming.service.PetShow;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertNotNull;
@ExtendWith(SpringExtension.class)
public class SpringBeanNamingUnitTest {
private AnnotationConfigApplicationContext context;
@BeforeEach
void setUp() {
context = new AnnotationConfigApplicationContext();
context.scan("com.baeldung.springbean.naming");
context.refresh();
}
// To name a bean spring gets the class name and converts the first letter to lowercase.
// Default naming strategy of the spring bean which is using class level annotation
@Test
void givenLoggingServiceBeanIsCreated_whenThereIsNoValueProvided_thenBeanNameShouldBeDefaultName() {
assertNotNull(context.getBean("loggingService"));
}
// In this case, to name a bean spring gets the class name and converts the first letter to lowercase.
@Test
void givenAuditServiceBeanIsCreatedWithMethodLevelAnnotation_whenThereIsNoValueProvided_thenBeanNameShouldBeTheNameOfMethod() {
assertNotNull(context.getBean("audit"));
}
// spring will create the bean of type CustomComponent with the name "myBean".
// As we're explicitly giving the name to the bean, spring will use this name to refer to it.
@Test
void givenCustomComponentBeanIsCreate_whenThereIsCustomNameGivenToBean_thenBeanShouldBeIdentifiedByThatName() {
assertNotNull(context.getBean("myBean"));
}
@Test
void givenCustomComponentBeanIsCreated_whenCustomNameIsGivenOnMethodLevelAnnotation_thenBeanShouldBeIdentifiedByThatName() {
assertNotNull(context.getBean("beanComponent"));
assertNotNull(context.getBean("configuration"));
assertNotNull(context.getBean("qualifierComponent"));
}
@Test
void givenMultipleImplementationsOfAnimal_whenFieldIsInjectedWithQualifiedName_thenTheSpecificBeanShouldGetInjected() {
PetShow petShow = (PetShow) context.getBean("petShow");
assertNotNull(context.getBean("cat"));
assertNotNull(context.getBean("dog"));
assertThat(petShow.getCat().getClass()).isEqualTo(Cat.class);
assertThat(petShow.getDog().getClass()).isEqualTo(Dog.class);
}
}