Як працює електропроводка навесні?


510

Я трохи збентежений, як працює інверсія управління ( IoC) Spring.

Скажімо , у мене є клас служби з ім'ям , UserServiceImplякий реалізує UserServiceінтерфейс.

Як би це було @Autowired?

І по-моєму Controllers, як би я instantiateотримав instanceцю послугу?

Я би просто зробив таке?

UserService userService = new UserServiceImpl();

Відповіді:


703

По-перше, і найголовніше - усіма весняними бобами керують - вони "живуть" всередині контейнера, який називається "контекст програми".

По-друге, кожна програма має точку входу до цього контексту. У веб-додатках є сервлет, JSF використовує el-резольвер і т. Д. Також є місце, де контекст програми завантажується, а всі боби - автоматичні. У веб-додатках це може бути слухач запуску.

Автоматичне підключення відбувається, розміщуючи екземпляр одного квасоля в потрібному полі в екземплярі іншого. Обидва класи повинні бути бобовими, тобто їх слід визначати, щоб вони жили в контексті програми.

Що таке "життя" в контексті програми? Це означає, що контекст створює об'єкти, а не вас. Тобто - ти ніколи не робиш 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="..">або використовуючи @Serviceпримітку. Оскільки він буде єдиним реалізатором UserService, він буде впорсований.
  • Крім @Autowiredанотації, Spring може використовувати автоматичну електропроводку, що налаштовується на XML. У цьому випадку всі поля, які мають ім’я або тип, які відповідають наявному бобу, автоматично отримують боб. Фактично, це була початкова ідея автопроводки - мати поля, які вводяться залежностями без будь-якої конфігурації. Інші анотацій подобається @Inject, @Resourceтакож можуть бути використані.

7
так, UserServiceImpl позначається службою, а UserService - інтерфейсом
Божо

16
область за замовчуванням є однотонною, тому у вас буде лише один екземпляр боба, який вводиться в декілька місць. Якщо ви чітко визначите область "прототипом", то існуватиме кілька примірників, можливо, ліниві (залежно від конфігурації)
Божо

2
Дякую велике за вашу посаду, мені це справді з’ясувалось. Щодо "Оскільки це буде єдиний реалізатор або UserService, він буде введений". - що робити, якщо існує кілька класів, які реалізують Userservice? Як Spring знає, яку реалізацію він повинен використовувати?
Шишігами

7
якщо є одна, визначена як "первинна", вона використовує її. Інакше це кидає виняток
Божо

3
ні, користувачСервіс створюється лише один раз, він знаходиться в одиночному діапазоні
Божо

64

Залежить від того, ви хочете маршрут анотацій або маршрут визначення біта 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
}

Коли він побачить @Autowired, Spring буде шукати клас, який відповідає властивості в applicationContext, і вводить його автоматично. Якщо у вас більше одного UserServiceквасолі, то вам доведеться визначити, який з них він повинен використовувати.

Якщо ви зробите наступне:

UserService service = new UserServiceImpl();

Він не забратиме, @Autowiredякщо ви не встановите його самостійно.


2
Тож у чому полягає використання визначення bean idв applicationContext.xml. Нам доведеться визначити userServiceзмінну з UserServiceтипом. То навіщо робити запис у xmlфайл.
гадюка

20

@Autowired є анотацією, представленою навесні 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.
Дмитро Міньковський

@dimadima Отже, якщо він робить System.out.println ("Значення ідентифікатора класу A" + a.getId ()) ;, а не як він насправді це зробив, буде правильніше. Будь ласка, дайте відповідь, оскільки цей інтуїтивно зрозумілий для мене і відповідно до мого сучасного рівня розуміння пояснює автоматичну проводку.
Джон Дої

Автомобільна анотація вводиться навесні 2,5 docs.spring.io/spring-framework/docs/2.5.x/api/org/…
SpringLearner

1
Для кращого розуміння, оскільки я новачок у цьому, чи @autowired інстанціює клас A за допомогою конструктора за замовчуванням? ЯКЩО НЕ ТАК, то як значення отримують миттєво в бобі або службі, якщо ми використовуємо автоматичне з'єднання. Я думаю, якщо він називає конструктор за замовчуванням, навіщо в першу чергу використовувати автопроводку, просто зробіть A a = new A (). Будь ласка, поясніть?
Самер

@Sameer Завдяки функції автоматичного підключення ви можете зберегти багато кодової панелі у ваших тестових одиницях, а також в класах контролерів, сервісів та дао, тому що опис полів приходить автоматично. Не потрібно викликати конструктора.
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файлі боб служби . Після цього вам потрібно імпортувати цей ServiceConfigurationклас до свого WebApplicationConfigurationкласу, щоб ви могли автоматично передати цей боб у свій контролер таким чином:

public class AccController {

    @Autowired
    private UserService userService;
} 

Ви можете знайти тут ДОУ на основі конфігурації Java приклад .


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

    }

У наведеному вище прикладі Весна шукає та впорскує, userServiceколи UserControllerстворено.

2. @Autowiredна сеттер

@AutowiredАнотації можна використовувати на сеттерів. У наведеному нижче прикладі, коли анотація використовується для методу setter, метод setter викликається з екземпляром, userServiceколи 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

Простими словами Автопроводка, з'єднання проводів автоматично, тепер виникає питання, хто це робить і який тип електропроводки. Відповідь: Контейнер робить це, і вторинний тип проводки підтримується, примітиви потрібно робити вручну.

Питання: Як контейнер знає, який тип електропроводки?

Відповідь: ми визначаємо його як byType, byName, конструктор.

Питання: Чи є спосіб, яким ми не визначимо тип автопроводки?

Відповідь: Так, там, роблячи одну примітку, @Autowired.

Питання: Але як система знає, мені потрібно вибрати цей тип вторинних даних?

Відповідь: Ви надасте ці дані у вашому файлі spring.xml або використовуючи анотації стеротипів до свого класу, щоб контейнер міг сам створювати об’єкти для вас.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.