Spring에서 자동 배선은 어떻게 작동합니까?


510

나는 방법으로 혼란 조금 해요 제어의 반전 ( IoC)에서 작동합니다 Spring.

인터페이스 UserServiceImpl를 구현 하는 서비스 클래스가 있다고 가정 해보십시오 UserService.

이것은 어떻게 @Autowired될까요?

그리고 내에서 Controllers, 어떻게 것 I 이 서비스를?instantiateinstance

그냥 다음을할까요?

UserService userService = new UserServiceImpl();

답변:


703

첫째, 가장 중요한-모든 스프링 빈은 관리되고 있으며 "응용 프로그램 컨텍스트"라는 컨테이너 안에 "살아"있습니다.

둘째, 각 응용 프로그램에는 해당 컨텍스트에 대한 진입 점이 있습니다. 웹 응용 프로그램에는 서블릿이 있고 JSF 는 el-resolver 등을 사용합니다. 또한 응용 프로그램 컨텍스트가 부트 스트랩되고 모든 Bean이 자동 연결되는 곳이 있습니다. 웹 애플리케이션에서 이것은 시작 리스너 일 수 있습니다.

자동 배선은 한 Bean의 인스턴스를 다른 Bean 인스턴스의 원하는 필드에 배치하여 발생합니다. 두 클래스는 모두 Bean이어야합니다. 즉, 응용 프로그램 컨텍스트에 맞게 정의되어야합니다.

응용 문맥에서 "생존"이란 무엇입니까? 이는 컨텍스트가 사용자가 아닌 객체를 인스턴스화 한다는 것을 의미 합니다. 즉, 절대 만들지 않습니다 new UserServiceImpl(). 컨테이너는 각 주입 지점을 찾아 인스턴스를 설정합니다.

컨트롤러에는 다음이 있습니다.

@Controller // Defines that this class is a spring bean
@RequestMapping("/users")
public class SomeController {

    // Tells the application context to inject an instance of UserService here
    @Autowired
    private UserService userService;

    @RequestMapping("/login")
    public void login(@RequestParam("username") String username,
           @RequestParam("password") String password) {

        // The UserServiceImpl is already injected and you can use it
        userService.login(username, password);

    }
}

몇 가지 참고 사항 :

  • 당신에 applicationContext.xml당신은 활성화해야 <context:component-scan>수업이 검사되도록 @Controller, @Service등 주석.
  • Spring-MVC 애플리케이션의 진입 점은 DispatcherServlet이지만 숨겨져 있기 때문에 애플리케이션 컨텍스트의 직접적인 상호 작용 및 부트 스트랩은 배후에서 발생합니다.
  • UserServiceImpl주석을 사용 <bean id=".." class="..">하거나 사용 하여 Bean으로 정의해야합니다 @Service. 의 유일한 구현 자이므로 UserService주입됩니다.
  • @Autowired주석 외에도 Spring은 XML 구성 가능한 자동 배선을 사용할 수 있습니다. 이 경우 기존 Bean과 일치하는 이름 또는 유형을 가진 모든 필드는 자동으로 Bean을 가져옵니다. 사실, 그것은 자동 배선의 초기 아이디어였습니다. 필드를 구성하지 않고 의존성으로 필드를 주입하십시오. 다른 주석처럼 @Inject, @Resource또한 사용할 수 있습니다.

7
예, UserServiceImpl은 Service로 주석을 달고 UserService는 인터페이스입니다.
Bozho

16
기본 범위는 싱글 톤이므로 Bean의 인스턴스는 하나만 있으며 이는 여러 위치에 주입됩니다. 범위를 "프로토 타입"으로 명시 적으로 정의하면 여러 인스턴스가 존재할 수 있습니다 (구성에 따라 다름)
Bozho

2
귀하의 게시물에 감사드립니다. 실제로 나를 위해 정리했습니다. '유일한 구현 자 또는 UserService이므로 주입됩니다.' Userservice를 구현하는 클래스가 여러 개인 경우 어떻게해야합니까? Spring은 어떤 구현을 사용해야하는지 어떻게 알 수 있습니까?
Shishigami

7
"기본"으로 지정된 것이 있으면이를 사용합니다. 그렇지 않으면 예외가 발생합니다
Bozho

3
아니요, userService는 한 번만 작성되며 singleton-scope에 있습니다.
Bozho

64

주석 경로를 원하는지 아니면 Bean XML 정의 경로를 원하는지에 따라 다릅니다.

에 콩을 정의했다고 가정 해보십시오 applicationContext.xml.

<beans ...>

    <bean id="userService" class="com.foo.UserServiceImpl"/>

    <bean id="fooController" class="com.foo.FooController"/>

</beans>

자동 배선은 응용 프로그램이 시작될 때 발생합니다. 따라서 fooController인수에 대해 UserServiceImpl클래스 를 사용하려는 에서는 다음과 같이 주석을 달 것입니다.

public class FooController {

    // You could also annotate the setUserService method instead of this
    @Autowired
    private UserService userService;

    // rest of class goes here
}

이 표시되면 @AutowiredSpring 은의 속성과 일치하는 클래스를 찾아 applicationContext자동으로 주입합니다. 하나 이상의 UserServiceBean 이있는 경우 사용할 Bean을 규정해야합니다.

다음을 수행하는 경우 :

UserService service = new UserServiceImpl();

@Autowired직접 설정하지 않으면 픽업하지 않습니다 .


2
그래서 정의의 사용 무엇 bean id에가 applicationContext.xml. 타입으로 userService변수 를 정의해야 합니다 UserService. 그래서 왜 xml파일에 항목을 작성 하십시오.
독사

20

@Autowired Spring 2.5에서 소개 된 주석으로, 주입에만 사용됩니다.

예를 들면 다음과 같습니다.

class A {

    private int id;

    // With setter and getter method
}

class B {

    private String name;

    @Autowired // Here we are injecting instance of Class A into class B so that you can use 'a' for accessing A's instance variables and methods.
    A a;

    // With setter and getter method

    public void showDetail() {
        System.out.println("Value of id form A class" + a.getId(););
    }
}

10
이것은 컴파일되지 않으며 일반적으로 올바르지 않습니다. @Autowired" B클래스의 클래스에 있는 모든 함수 (방법) 및 변수를 사용할 수 있습니다"는 의미는 아닙니다 A. 그것이 무엇 것은 인스턴스 제공 A의 인스턴스로를 B, 그래서 당신은 할 수 a.getId()에서 B.
Dmitry Minkovsky

@dimadima 따라서 System.out.println ( "id form A class"+ a.getId ());를 수행하면 실제로 수행 한 것이 아니라면 더 정확합니다. 이것은 직관적으로 명확하고 현재의 이해 수준에 따라 Autowiring을 설명하므로 답장을 보내주십시오.
John Doe


1
@autowired는 기본 생성자를 사용하여 클래스 A를 인스턴스화합니까? 그렇지 않다면 autowired를 사용하는 경우 Bean 또는 서비스에서 값을 인스턴스화하는 방법입니다. 기본 생성자를 호출하면 처음에 자동 배선을 사용하는 이유는 A a = new A ()입니다. 명확히 하시겠습니까?
Sameer

@Sameer Autowiring 의존성을 사용하면 필드의 인스턴스화가 자동으로 제공되므로 단위 테스트와 컨트롤러, 서비스 및 Dao 클래스에서 많은 상용구 코드를 저장할 수 있습니다. 생성자를 호출 할 필요가 없습니다.
kiltek

9

@Autowired내부적으로 어떻게 작동합니까?

예:

class EnglishGreeting {
   private Greeting greeting;
   //setter and getter
}

class Greeting {
   private String message;
   //setter and getter
}

.xml 파일을 사용하지 않으면 비슷하게 보입니다 @Autowired.

<bean id="englishGreeting" class="com.bean.EnglishGreeting">
   <property name="greeting" ref="greeting"/>
</bean>

<bean id="greeting" class="com.bean.Greeting">
   <property name="message" value="Hello World"/>
</bean>

당신이 사용하는 @Autowired경우 :

class EnglishGreeting {
   @Autowired //so automatically based on the name it will identify the bean and inject.
   private Greeting greeting;
   //setter and getter
}

.xml 파일을 사용하지 않으면 비슷하게 보입니다 @Autowired.

<bean id="englishGreeting" class="com.bean.EnglishGreeting"></bean>

<bean id="greeting" class="com.bean.Greeting">
   <property name="message" value="Hello World"/>
</bean>

여전히 의심이 있다면 라이브 데모 아래를 살펴보십시오.

@Autowired는 내부적으로 어떻게 작동합니까?


6

주석으로 서비스 클래스 UserServiceImpl에 주석 을 달기 만하면 됩니다.

@Service("userService")

스프링 컨테이너는 서비스로 등록 될 때이 클래스의 수명주기를 처리합니다.

그런 다음 컨트롤러에서 자동 배선 (인스턴스화)하고 기능을 사용할 수 있습니다.

@Autowired
UserService userService;

3

스프링 의존성 주입은 클래스에서 커플 링을 제거하는 데 도움이됩니다. 다음과 같은 객체를 만드는 대신 :

UserService userService = new UserServiceImpl();

DI를 소개 한 후에 이것을 사용할 것입니다 :

@Autowired
private UserService userService;

이를 위해서는 ServiceConfiguration파일에 서비스 Bean을 작성해야 합니다. 그런 다음 해당 ServiceConfiguration클래스를 클래스 로 가져 와서 WebApplicationConfiguration다음과 같이 해당 Bean을 Controller에 자동 와이어 링 할 수 있습니다.

public class AccController {

    @Autowired
    private UserService userService;
} 

현재 자바 구성을 기반으로 POC 찾을 수 있습니다 예를 들어 .


1

표준 방식 :

@RestController
public class Main {
    UserService userService;

    public Main(){
        userService = new UserServiceImpl();
    }

    @GetMapping("/")
    public String index(){
        return userService.print("Example test");
    }
}

사용자 서비스 인터페이스 :

public interface UserService {
    String print(String text);
}

UserServiceImpl 클래스 :

public class UserServiceImpl implements UserService {
    @Override
    public String print(String text) {
        return text + " UserServiceImpl";
    }
}

산출: Example test UserServiceImpl

이것은 꽉 결합 된 클래스, 나쁜 디자인 예제의 좋은 예이며 테스트에 문제가있을 것입니다 (PowerMockito도 나쁩니다).

이제 느슨한 결합의 좋은 예인 SpringBoot 의존성 주입을 살펴 보자.

인터페이스는 동일하게 유지됩니다.

메인 클래스 :

@RestController
public class Main {
    UserService userService;

    @Autowired
    public Main(UserService userService){
        this.userService = userService;
    }

    @GetMapping("/")
    public String index(){
        return userService.print("Example test");
    }
}

ServiceUserImpl 클래스 :

@Component
public class UserServiceImpl implements UserService {
    @Override
    public String print(String text) {
        return text + " UserServiceImpl";
    }
}

산출: Example test UserServiceImpl

이제 테스트를 작성하기 쉽습니다.

@RunWith(MockitoJUnitRunner.class)
public class MainTest {
    @Mock
    UserService userService;

    @Test
    public void indexTest() {
        when(userService.print("Example test")).thenReturn("Example test UserServiceImpl");

        String result = new Main(userService).index();

        assertEquals(result, "Example test UserServiceImpl");
    }
}

내가 보여 @Autowired생성자에 주석을하지만, 그것은 또한 세터 또는 필드에서 사용할 수 있습니다.


0

제어 역전의 전체 개념은 객체를 수동으로 인스턴스화하고 필요한 모든 종속성을 제공하는 번거 로움이 없음을 의미합니다. 적절한 주석 (예 :)으로 클래스에 주석을 달면 @ServiceSpring이 자동으로 객체를 인스턴스화합니다. 주석에 익숙하지 않은 경우 XML 파일을 대신 사용할 수도 있습니다. 그러나 new전체 스프링 컨텍스트를로드하지 않으려는 경우 단위 테스트에서 키워드를 사용하여 클래스를 수동으로 인스턴스화하는 것은 좋지 않습니다.


0

스프링 구성 파일에 @Autowired요소 <context:annotation-config/>를 추가 하여 주석을 활성화해야 합니다. AutowiredAnnotationBeanPostProcessor주석 처리를 담당하는 등록합니다 .

그리고 필드 주입 방법을 사용하여 서비스를 자동 와이어 링 할 수 있습니다.

public class YourController{

 @Autowired
 private UserService userService; 

}

나는 Spring @ autowired 주석 에서 이것을 발견했다.


0

을 사용하여 인스턴스를 만들 수있는 방법은 3 가지가 있습니다 @Autowired.

1. @Autowired속성

주석은 속성에 직접 사용될 수 있으므로 게터와 세터가 필요하지 않습니다.

    @Component("userService")
    public class UserService {

        public String getName() {
            return "service name";
        }
    }

    @Component
    public class UserController {

        @Autowired
        UserService userService

    }

위 예제에서 Spring 은 생성 userService될 때 찾아서 주입 UserController합니다.

2. @Autowired세터에서

@Autowired주석은 setter 메소드에서 사용할 수 있습니다. 아래 예제에서 주석이 setter 메소드에서 사용될 때 setter 메소드는 userServicewhen UserController가 작성된 인스턴스와 함께 호출됩니다 .

public class UserController {

    private UserService userService;

    @Autowired
    public void setUserService(UserService userService) {
            this.userService = userService;
    }
}

3. @Autowired생성자

@Autowired주석은 또한 생성자에서 사용할 수 있습니다. 아래 예제에서 생성자가 주석을 사용하는 경우 생성시 인스턴스의 인스턴스가 생성자에 userService대한 인수로 삽입됩니다 UserController.

public class UserController {

    private UserService userService;

    @Autowired
    public UserController(UserService userService) {
        this.userService= userService;
    }
}

0

간단히 말해서 자동 배선, 자동으로 링크 연결은 이제 누가이 작업을 수행하고 어떤 종류의 배선을 수행해야하는지에 대한 질문을받습니다. 답은 : 컨테이너가이를 수행하고 2 차 유형의 배선이 지원되므로 기본 요소를 수동으로 수행해야합니다.

질문 : 컨테이너는 어떤 유형의 배선을 알고 있습니까?

답변 : 우리는 그것을 byType, byName, 생성자로 정의합니다.

질문 : 자동 배선 유형을 정의하지 않는 방법이 있습니까?

답 : 예. @Autowired라는 주석 하나만 사용하면됩니다.

질문 : 그러나 시스템이 어떻게 알 수 있습니까?이 유형의 보조 데이터를 선택해야합니까?

답 : 컨테이너에서 스스로 객체를 생성 할 수 있도록 spring.xml 파일에 데이터를 제공하거나 클래스에 sterotype 주석을 사용하십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.