Конфигурация Spring бинов с помощью Java класса.

Иногда удобнее бывает конфигурировать бины не с помощью XML, а с помощью Java кода. То есть теперь вместо applicationContext.xml у нас будет Java класс.

Для начала давайте поправим класс ServerPC. Вернем в него конструктор, так как он будет использован в новом конфигурационном файле.

Класс ServerPC:

package com.someclasses; import org.springframework.stereotype.Component; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Scope; import org.springframework.beans.factory.annotation.PostConstruct; import org.springframework.beans.factory.annotation.PreDestroy; @Component(“serverPCBean”) @Scope(“singleton”) public class ServerPC{ @Autowired private Administrator admin; @Value(“${pcid}”) private String pcid; @Value(“Acer”) private String pcBrand; ServerPC() {} //Для начала давайте вернем конструктор, который //внедряет зависимость в бин класса ServerPC. //Он будет использоваться в Java классе конфигураций //для внедрения зависимости админа в бин ServerPC. public ServerPC(Administrator admin) { this.admin = admin; } public Administrator getAdmin() { return admin; } public void setPCid(String pcid) { this.pcid = pcid; } public void setPCBrand(String pcBrand) { this.pcBrand = pcBrand; } public String getPCid() { return pcid; } public String getPCBrand() { return pcBrand; } public void typeOfPC() { System.out.println(“Its server PC!”); } public void getAdminMessage(){ admin.adminMessage(); } @PostConstruct public String someInicializationsMethod() { return “Some inicializations”; } @PreDestroy public String someCleaningsMethod() { return “Some clean up”; } }

Конфигурационный Java класс:

import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.PropertySource; import com.someclasses.Administrator; import com.someclasses.ServerPC; //Для этого помечаем класс //конфигураций аннотацией configuration @Configuration //@ComponentScan это то же самое что // в XML //для сканирования папки с классами с аннотациями. @ComponentScan(“com.someclasses”) //@PropertySource это то же самое что // в XML. //То есть указываем файл из которого можем извлекать //значения для внедрения их в поля бинов. @PropertySource(“classpath:pc.properties”) public class ConfigClass { //теперь определим бины как в xml только java кодом. //Аннотация @Bean определяет что нижний //метод это определение бина. @Bean //имя метода то есть someUser – это id как в xml. //Возвращаемое значение это класс на основе //которого будет создаваться бин. public Administrator admin(){ //Метод создает бин и возвращает его. return new Administrator(); //BeanFactory когда будет читать этот файл вызовет //этот метод, этот метод как видим создает и возвращает //новый объект Administrator то есть бин и этот созданный //бин будет хранится в объекте BeanFactory, который //можно будет оттуда извлечь. } @Bean public ServerPC serverPC(){ //Для внедрения бина Administrator в другой бин //его нужно для начала создать. //Для этого можно вызывать ранее //определенный метод admin(), который возвращает //бин класса Administrator и передать этот бин //в конструктор нового бина класса ServerPC. //Таким образом с помощью метода serverPC() //BeanFactory создает новый бин класса ServerPC //с внедренной зависимостью. return new ServerPC(admin()); } }

Теперь создадим класс сервлета, в котором бины будут создаваться на основе конфигурационного Java класса.

import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import java.io.*; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import com.someclasses.ServerPC; @WebServlet(“/springservlet”) public class SpringServlet extends HttpServlet{ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //Для создания объекта BeanFactory на основе //Java конфигураций используется уже другая //реализация BeanFactory. //Теперь вместо ClassPathXmlApplicationContext //будет объект AnnotationConfigApplicationContext. AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( ConfigClass.class); //Достаем бин serverPC, который мы определили //в ConfigClass из context. ServerPC serverpcSingleton = context.getBean( “serverPC”,ServerPC.class); //используем бин serverpcSingleton.setPCid(“12353425”); resp.getWriter().write(serverpcSingleton.getPCid()); } }

Проверка работы приложения

Компилируем Java файлики включая новый класс с конфигурациями с использованием jar файлов спринг:

Запускаем Tomcat и открываем страницу сервлета по пути /springservlet:

Как видим, бины были успешно созданы и мы ими успешно воспользовались.

Аннотация @Autowired в Spring Framework

В прошлом уроке мы внедряли бин админа в бин ПК с помощью конструктора или сеттера помеченных аннотацией @Autowired. Но аннотация @Autowired намного мощнее.

Если мы просто пометим нужное поле в классе аннотацией @Autowired, нам даже не нужно будет писать конструктор или сеттер для внедрения этого поля в бин, который создается на основе этого класса. Тем самым можно сократить количество кода в классе.

Класс ServerPC:

package com.someclasses; import org.springframework.stereotype.Component; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Scope; import org.springframework.beans.factory.annotation.Value; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; @Component(“serverPCBean”) @Scope(“singleton”) public class ServerPC { //Аннотация Autowired может внедрять //зависимости без написаного конструктора или сеттера. //Аннотацию нужно просто написать над полем, которое //должно быть внедрено извне @Autowired private Administrator admin; @Value(“${pcid}”) private String pcid; @Value(“Acer”) private String pcBrand; ServerPC () { } //Нижние два метода для внедрения user в бин //этого класса теперь можно закомментировать. /* @Autowired public ServerPC (Administrator admin) { this.admin = admin; } @Autowired public void setAdmin(Administrator admin) { this.admin = admin; } */ public Administrator getAdmin() { return admin; } public void setPcid(String pcid) { this.pcid = pcid; } public void setPCBrand(String pcBrand) { this.pcBrand = pcBrand; } public String getPcid() { return pcid; } public String getPCBrand() { return pcBrand; } public void typeOfPC() { System.out.println(“Its server PC!”); } public void getAdminMessage() { admin.adminMessage(); } //Помечаем метод инициализации //(как в xml init-method) @PostConstruct public String someInitializationsMethod() { return “Some initializations”; } //Помечаем метод, который выполняется при //уничтожении бина (как в xml destroy-method) @PreDestroy public String someCleaningsMethod() { return “Some clean up”; } }

Класс сервлета останеться без изменений.

Пример программы:

import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import java.io.*; import org.springframework.context. support.ClassPathXmlApplicationContext; import com.someclasses.ServerPC; @WebServlet(“/springservlet”) public class SpringServlet extends HttpServlet{ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( “applicationContext.xml”); //Достаем бин из context ServerPC serverpcSingleton = context.getBean( “serverPCBean”,ServerPC.class); //используем бин serverpcSingleton.setPCid(“12353425”); resp.getWriter().write(serverpcSingleton.getPCid()); } }

Компилируем Java файлики с использованием jar файлов спринг:

Запускаем Tomcat и открываем страницу сервлета по пути /springservlet:

Как видим, бины были успешно созданы и мы ими успешно воспользовались.

Конфигурация Spring бинов с помощью аннотаций

Как уже было упомянуто в конце прошлого урока, бины можно создавать не в applicationContext.xml, а аннотациями прямо в классах бинов.

Благодаря этому можно не писать огромное количество xml кода.

Можно создать вот такие бины, вот таким образом с помощью xml:

Идентичный бин класса ServerPC можно сконфигурировать с помощью аннотаций сразу в классе бина:

package com.someclasses; import org.springframework.stereotype.Component; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Scope; import org.springframework.beans.factory.annotation.Qualifier; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; //С помощью Component помечаем что //на основе этого класса будет создан бин. //В скобочках указываем id бина. @Component(“serverPCBean”) //эго Scope только аннотацей @Scope(“singleton”) public class ServerPC{ private Administrator admin; //С помощью Value записывается //значение в поле бина. //Здесь из файла pc.propreites в String поле @Value(“${pcid}”) private String pcid; @Value(“Acer”) private String pcBrand; ServerPC() {} //С помощью Autowired происходит DI. //Spring ищет в папке someclasses //класс Administrator (класс Administrator //и ServerPC лежат в папке classes/com/someclasses, //можно увидеть сверху package com.someclasses;) //который тоже помечен аннотацией Component //и потом создает бин класса Administrator //и внедряет его в текущий бин serverPCBean. @Autowired public ServerPC(Administrator admin) { this.admin = admin; } //Это внедрение с помощью сеттера. //Кстати @Autowired можно //применить не только на сеттер, //а вообще на метод с любым именем //в этом классе который внедряет зависимость. @Autowired public void setAdmin(Administrator admin) { this.admin = admin; } public Administrator getAdmin() { return admin; } public void setPcid(String pcid) { this.pcid = pcid; } public void setPCBrand(String pcBrand) { this.pcBrand = pcBrand; } public String getPCid() { return pcid; } public String getPCBrand() { return pcBrand; } public void typeOfPC() { System.out.println(“Its server PC!”); } public void getAdminMessage() { admin.adminMessage(); } //Помечаем метод инициализации //(как в xml init-method) @PostConstruct public String someInitializationsMethod() { return “Some initializations”; } //Помечаем метод который выполняется при //уничтожении бина (как в xml destroy-method) @PreDestroy public String someCleaningMethod() { return “Some clean up”; } }

Также в классе администратор тоже пишем аннотацию Component, чтобы создался бин на основе этого класса и внедрился в бин ПК:

package com.someclasses; import org.springframework.stereotype.Component; @Component() public class Administrator{ public String adminMessage(){ return “I’m an administrator!”; } }

В файле же applicationContext.xml нам нужно указать где находятся файлики классов, которые мы только что создали, чтобы BeanFactory нашел их и создал на основе этих файлов с аннотациями бины.

applicationContext.xml:

Давайте же проверим создадутся ли бины в сервлете.

Пример программы:

import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import java.io.*; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.someclasses.ServerPC; @WebServlet(“/springservlet”) public class SpringServlet extends HttpServlet{ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //Объект Beanfactory //анализирует applicationContext.xml, //видит что там указано что нужно искать //классы с аннотациями в папке com/someclasses, //объект Beanfactory анализирует эту папку //и создает на основе этих классов бины. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( “applicationContext.xml”); //Достаем бин из context ServerPC serverpcSingleton = context.getBean( “serverPCBean”,ServerPC.class); //используем бин serverpcSingleton.setPcId(“12353425”); resp.getWriter().write(serverpcSingleton.getPcId()); } }

Проверка работы приложения

Компилируем Java файлики с использованием jar файлов спринг:

Запускаем Tomcat и открываем страницу сервлета по пути /springservlet:

Как видим, быны были успешно созданы и мы ими успешно воспользовались.

Search Icon

При всех плюсах такого подхода конфигурации бинов, ясное дело, у такого подхода есть маленький минус, что много бинов на основе одного и того же класса аннотациями не определишь, поэтому если нам нужно создать еще один бин с другим id на основе класса ServerPC, то нужно определять его в applicationContext.

Жизненный цикл Spring-бина

Жизненный цикл спринг бина таков:

  1. В Java программе создается объект BeanFactory
  2. В нем создаются бины и внедряются зависимости
  3. Потом вызывается метод указанный в init-method у бина в конфигурационном xml файле
  4. Потом созданные бины в BeanFactory извлекаются оттуда и используются
  5. Вызов context.close() завершает работу BeanFactory и при этом уничтожаются бины, но перед этим вызывается метод указанный в destroy-method.

Что же это за init-method и destroy-method?

Это что-то типа init и destroy методов в сервлете. Как мы помним, init метод нужен в сервлете для инициализации каких-то данных при создании объекта сервлета, а destroy метод нужен для освобождения каких-то ресурсов перед уничтожением объекта сервлета.

init-method и destroy-method, это то же самое, только с бином.

init и destroy методы определяются в классе бина. Могут иметь любое имя. Давайте же добавим их в класс ServerPC.

ServerPC:

package com.someclasses; public class ServerPC{ private Administrator admin; private String pcid; private String pcBrand; ServerPC() {} //Чтобы продемонстрировать жизненный цикл //бина добавим вывод строки на консоль //при внедрении в бин другого бина //с помощью конструктора ниже. эта строка //выведется на консоль раньше чем те которые //выводят новые init, destroy методы ниже. ServerPC(Administrator admin) { this.admin = admin; System.out.println(“Bean is Created!”); } //это init метод он вызывается сразу после //создания бина класса ServerPC public void someInicializationsMethod() { System.out.println(“Some inicializations”); } //это destroy метод он вызывается перед //уничтожением BeanFactory и перед уничтожением //бинов. public void someCleaningsMethod() { System.out.println(“Some clean up”); } public void setAdmin(Administrator admin) { this.admin = admin; } public Administrator getAdmin() { return admin; } public void setPCid(String pcid) { this.pcid = pcid; } public void setPCBrand(String pcBrand) { this.pcBrand = pcBrand; //В этом сеттере тоже добавим //вывод строки на консоль. Тоже для //демонстрации жизненного цикла. System.out.println(“Bean in use!”); } public String getPCid() { return pcid; } public String getPCBrand() { return pcBrand; } public String getAdminMessage(){ return admin.adminMessage(); } }

Давайте сконфигурируем два бина. Один будет с scope singleton, другой с scope prototype. И определим у них init и destroy методы.

applicationContext.xml:

Теперь давайте в сервлете создадим, извлечем, используем и уничтожим бины в определенной последовательности для демонстрации жизненного цикла бина.

Пример программы:

import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import java.io.*; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.someclasses.ServerPC; @WebServlet(“/springservlet”) public class SpringServlet extends HttpServlet{ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //при создании BeanFactory создаётся бин со //скоупом singleton и сразу после его создания //у него вызывается метод инициализации, который //был у него указан в атрибуте init-method. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( “applicationContext.xml”); //После создания бинов в context //пусть выведется любое сообщение в сервлете. System.out.println(“Some message”); //Достаем бин из context ServerPC serverpcSingleton = context.getBean( “serverPCBeanSingletonScope”,ServerPC.class); //используем бин serverpcSingleton.setPCid(“12353425”); System.out.println(serverpcSingleton.getPCid()); //Бин же со скоупом prototype создаётся //при вызове getBean и соответственно //init метод указанный у него в init-method //вызывается при вызове getBean. ServerPC serverpcPrototype = context.getBean( “serverPCBeanPrototypeScope”,ServerPC.class); //используем другой бин serverpcPrototype.setPCid(“4567452563”); System.out.println(serverpcPrototype.getPCid()); //Перед удалением объекта BeanFactory //и бинов в нем вызывать destroy //метод someCleaningsMethod context.close(); } }

Компилируем Java файлики. Файл сервлета при этом компилируем с использованием jar файлов спринг:

Запускаем Tomcat и открываем страницу сервлета по пути /springservlet и смотрим в консоль Tomcаt сервера:

Как видим, сразу создался бин со скоупом синглтон. об этом говорит строка Bean is Created!, которую выводит конструктор при создании бина serverPCBeanpSingletonScope.

Сразу после создания этого бина вызывается init метод, который выводит строку Some initializations.

Создание бина синглтона же случилось при создании Beanfactory, а не при вызове getBean этого бина. Это доказывает третья строка в консоли, которая выведена в консоль между созданием объектаа BeanFactory и вызовом getBean бина синглтона.

Далее мы воспользовались этим бином вывели у него значение поля.

Теперь же создается бин serverPCBeanpPototypeScope со скоупом prototype когда вызывается getBean этого бина. При этом, конструктор выводит сообщение при создании бина и сразу после этого вызывается метод инициализации, который тоже выводит сообщение.

После этого этот бин используется. Выводиться значение его поля.

И в конце программы вызывается context.close(); который перед удалением бинов и объекта BeanFactory вызывает destroy метод, который выводит последнюю Some Clean Up.


Выводы о Spring Framework

И в итоге можно еще не до конца понимать зачем нужен этот ваш Spring Framework, все эти бины, если создание и внедрение бинов можно с легкостью выполнять в java классе кодом:

Administrator admin = new Administrator();

ServerPC serverPC = new ServerPC(admin);

Таких DI "матрешек" в обычном (не спринг) веб-приложении с большим количеством классов будет очень много, а Spring Framework предлагает вынести их в отдельный конфигурационный файл и спринг сам будет создавать объекты сконфигурированных бинов и устанавливать зависимости, а java код самого приложения будет чист нам останется лишь только извлечь созданные объекты из пула объектов созданных спрингом.

Может показаться кода в целом стало больше (код конф файла плюс некоторый код для извлечения бинов в самом приложении), но истенный смысл Spring Framework становится очевидным только разработчикам, которым приходилось вручную управлять всеми этими DI «матрёшками» в крупных не-Spring проектах. Когда мы дойдем до Spring аннотаций о смысле Spring Framework не придется задумываться, там не нужно будет конфигурировать бины в отдельном файле и писать много кода, их конфигурация будет происходить простыми аннотациями в коде классов.

Также, поскольку спринг сам берет на себя ответственность за создание объектов, он может и добавлять к ним некоторую доп функциональность (какую-то мы уже видели – добавление скоупов, методов при иниц. или уничтожении).

Search Icon

Функциональность Spring сегодня уже не ограничивается просто созданием и внедрением бинов. Spring сегодня предоставляет огромное количество различных средств для разработки Веб-приложений, которые будут рассмотрены в этом курсе.

Области видимости бинов (Spring Scopes)

Бин может иметь область, в которой он действует.

Их 5: singleton, prototype, request, session и global-session.

По дефолту scope у бина singleton. Это значит, что если мы в коде сервлета запишем.

ServerPC serverpc = context.getBean(“serverPCBean”,ServerPC.class); ServerPC serverpc1 = context.getBean(“serverPCBean”,ServerPC.class);

то и serverpc и serverpc1 будут ссылаться на один и тот же объект поскольку как помним у синглтона может быть только один экземпляр.

Если бину serverPCBean в конф. файле установить scope="prototype", то в приведенном примере создадутся два разных экземпляра.

Также есть:

  • request (при каждом запросе к сервлету создается новый экземпляр (bean)),
  • session (при каждой новой сессии пользователя создается новый экземпляр (bean))
  • global-session (экземпляр распространяется на всё приложение).

Давайте сконфигурируем два бина. У одного будет scope singleton у другого prototype.

applicationContext.xml:

Давайте же теперь проверим определенные бины и их скоупы в Java программе.

Пример программы:

import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import java.io.*; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.someclasses.ServerPC; @WebServlet(“/springservlet”) public class SpringServlet extends HttpServlet{ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( “applicationContext.xml”); //Поскольку serverPCBeanpSingletonScope //имеет scope singleton ниже //создадутся две ссылки на один //и тот же объект serverPCBeanpSingletonScope. //То есть при каждом вызове getBean из context //извлекается один и тот же //объект serverPCBeanpPototypeScope ServerPC serverpcSingleton = context.getBean( “serverPCBeanpSingletonScope”,ServerPC.class); ServerPC serverpcSingleton1 = context.getBean( “serverPCBeanpSingletonScope”,ServerPC.class); //Проверим правда ли обе ссылки ссылаются //на один и тот же объект //serverPCBeanpSingletonScope. //Установим значение поля pcid //у бина serverPCBeanpSingletonScope //через ссылку serverpcSingleton, serverpcSingleton.setPcid(“1233425”); //и теперь извлечем его //через другую ссылку – serverpcSingleton1 resp.getWriter().write( serverpcSingleton1.getPcid()); //Поскольку serverPCBeanpPototypeScope //имеет scope prototype ниже //создадутся две ссылки на разные //объекты serverPCBeanpPototypeScope. //То есть при каждом вызове getBean создается //новый объект serverPCBeanpPototypeScope ServerPC serverpcPrototype = context.getBean( “serverPCBeanpPototypeScope”,ServerPC.class); ServerPC serverpcPrototype1 = context.getBean( “serverPCBeanpPototypeScope”,ServerPC.class); //Проверим правда ли обе ссылки ссылаются //на разные объекты serverPCBeanpPototypeScope. //Установим значение поля pcid //у бина serverPCBeanpPototypeScope //через ссылку serverpcPrototype, serverpcPrototype.setPcid(“1233425”); //и теперь извлеч это значение через //ссылку serverpcPrototype1 не получится //так как serverpcPrototype1 ссылается //на другой объект. resp.getWriter().write( serverpcPrototype1.getPcid()); } }

Компилируем Java файлики. Файл сервлета при этом компилируем с использованием jar файлов спринг:

Запускаем Tomcat и открываем страницу сервлета по пути /springservlet:

Как видим выведено было pcid только у бина синглтона. Через первую ссылку на него serverpcSingleton мы установили значение поля pcid, а через вторую ссылку serverpcSingleton1 на него вывели это значение.

В случае же с serverPCBeanpPototypeScope создавалось два бина и ссылки ссылались на разные обьекты, поэтому через ссылку serverpcPrototype1 ничего не вывести не получилось.

Теперь должно быть понятно что представляют собой скоупы. Остальные же скоупы демонстрировать не будем так как там ничего особо сложного нет.

Внедрение значений из внешнего файла в поля Spring бина.

Внедрять значения в поля бина можно не напрямую, а из внешнего файла. Давайте же создадим такой файл, в котором будут харнится данные в формате имя-значение. По имени мы сможем извлечь значение из этого файла для использования его в конф файле. Пусть пока в нем будет всего одно значение с именем pcid.

Пусть этот файл будет называться pc.propreties и пока пусть находиться в той же папке, что и applicationContext.xml и класс сервлета.

Файл со значениями:


Внедрение значений из внешнего файла в поля бина.

Давайте же теперь внедрим строковое значение в поле pcid бина класса ServerPC но уже не напрямую, а из созданного нами ранее файла.

applicationContext.xml:

c

Внедрение значений из внешнего файла в поля бина.

Давайте же теперь в классе сервлета извлечем сконфигурированный бин и проверим внедрилось ли в его поле строковое значение из файла.

Пример программы:

import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import java.io.*; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.someclasses.ServerPC; @WebServlet(“/springservlet”) public class SpringServlet extends HttpServlet{ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( “applicationContext.xml”); //Теперь извлечем новый бин serverPCBeanSetter ServerPC serverpc = context.getBean(“serverPCBeanSetter”,ServerPC.class); resp.getWriter().write(serverpc.getPCid()); } }

Проверка работы приложения

Теперь проверим содержимое поля pcid созданного бина.

Компилируем Java файлики. Файл сервлета при этом компилируем с использованием jar файлов спринг:

Запускаем Tomcat и открываем страницу сервлета по пути /springservlet:

Как видим, значение из файла внедрилось в поле бина успешно.

Внедрение зависимостей в Spring с помощью сеттера.

Помним, что в прошлом уроке внедрение админа в ПК происходило с помощью конструктора в классе ПК.

Но внедрять также можно с помощью сеттера

Класс ServerPC:

package com.someclasses; public class ServerPC{ private Administrator admin; private String pcid; private String pcBrand; ServerPC() {} ServerPC(Administrator admin) { this.admin = admin; } //Теперь внедрение будет происходить //с помощью этого сеттера. public void setAdmin(Administrator admin){ this.admin = admin; } public Administrator getAdmin() { return admin; } public void setPcid(String pcid) { this.pcid = pcid; } public void setPCBrand(String pcBrand) { this.pcBrand = pcBrand; } public String getPCid() { return pcid; } public String getPCBrand() { return pcBrand; } public String getAdminMessage(){ return admin.adminMessage(); } }

Теперь давайте в конфигурациях определим новый бин Серверного ПК, в который внедрять бин админа будем уже с помощью сеттера класса серверного ПК.

applicationContext.xml:


Создание и получение бинов в Java программе.

Давайте же теперь в классе сервлета извлечем сконфигурированный бин и проверим внедрился ли в него бин админа с помощью сеттера.

Пример программы:

import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import java.io.*; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.someclasses.ServerPC; @WebServlet(“/springservlet”) public class SpringServlet extends HttpServlet{ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( “applicationContext.xml”); //Теперь извлечем новый бин serverPCBeanSetter ServerPC serverpc = context.getBean(“serverPCBeanSetter”,ServerPC.class); resp.getWriter().write(serverpc.getAdminMessage()); } }

Проверка работы приложения

Теперь проверим скажет ли администратор “I’m an administrator!”.

Компилируем Java файлики. Файл сервлета при этом компилируем с использованием jar файлов спринг:

Запускаем Tomcat и открываем страницу сервлета по пути /springservlet :

Как видим сказал. То есть объект админа был успешно внедрен в объект ПК с помощью сеттера.

Что такое Spring Framework и зачем он нужен

В разделе по сервлетам мы уже встречались с так называемыми бинами — это обычные объекты классов с приватными полями, геттерами и сеттерами.

Так вот, где-то до 2003 работать с бинами в Java EE было очень непростой, запутанной задачей.

Чтобы создавать и использовать бины нужно было писать очень много кода и продуктивность очень сильно страдала, так, что даже была написана книжка “Java EE без использования бинов” )))

Спринг фреймворк как раз нужен, чтобы упросить всё это дело. Для упрощения создания, конфигурации и взаимодействия бинов.


Dependency injection(DI), IoC(Inversion of Control)

Существует такая вещь, как DI (Dependency Injection) — внедрение зависимостей.

Этот паттерн можно было увидеть по ходу курса много раз. Вот он:

public class Car {   private Engine brand;       Car(Engine brand){        this.brand = brand;     }

То есть объект(бин) Engine в данном примере внедряется в другой бин Car через конструктор или сеттер извне. Объект, который внедряется еще называют зависимостью.

То есть суть в том, что два объекта разных классов отдельны друг о друга и нам их нужно как-то связать между собой, чтобы один объект пользовался другим и сделать это можно через такое внедрение.

В Spring за создание бинов и внедрение внешних зависимостей отвечает IoC Controller (BeanFactory).

IpC расшифровывается как Inversion of Control (инверсия контроля). Это тоже паттерн в соответствии с которым в приложении есть некоторая функциональность, которая выполняет некоторые действия за программиста, например, как в данном случае внедрение внешних зависимостей перекладывается с плеч программиста на Spring Framework и на IoC Controller в частности.


Установка Spring

Демонстрировать работу со Spring Framework будем в сервлет-среде, в которой мы уже работали.

Сервлет-среда не особо заточена под спринг, в принципе можно было бы показывать азы спринга и в обычном приложении с методом main, но давайте сразу работать с веб-средой, поскольку спринг всё таки в основном фреймворк для разработки веб-приложений.

Для начала, необходимо скачать jar файлы спринг, с помощью которых будем компилировать классы, в которых используется спринг.

Скачиваем по ссылке:

https://drive.google.com/file/d/19qPe8keK7dysIF0xzpJLQ--nP0OCL_51/view?usp=sharing

Закидываем содержимое архива в папку lib в WEB-INF.


Создание классов бинов

Для начала, давайте создадим классы бинов, объекты которых Spring Framework будет создавать и связывать с помощью DI.

Представим ситуацию, что администратор сел за серверный компьютер и сказал “Я администратор”.

Смоделируем эту ситуацию только с помощью бинов. То есть нам нужно создать бин Administrator и бин ServerPC. Бин Administrator будет внедряться в бин ServerPC. И этот бин администратор будет использован в бине серверный компьютер для вызова сообщения  “Я администратор!”.

Сначала давайте создадим класс бина, который будет внедряться в другой бин. То есть создадим класс администратора.

Сначала давайте :

package com.someclasses; public class Administrator{ public String adminMessage(){ return “I’m an administrator!”; } }

Теперь создадим класс бина, в который будет внедрятся и в котором будет использоваться созданный выше класс. То есть создадим класс Серверного ПК.

package com.someclasses; //Очень простой класс ничего нового //Поля, геттеры, сеттеры, конструктор. public class ServerPC{ private Administrator admin; private String pcid; private String pcBrand; ServerPC() {} //внедрение будет происходить //с помощью конструктора ServerPC(Administrator admin) { this.admin = admin; } public void setAdmin(Administrator admin) { this.admin = admin; } public Administrator getAdmin() { return admin; } public void setPCid(String pcid) { this.pcid = pcid; } public void setPCBrand(String pcBrand) { this.pcBrand = pcBrand; } public String getPCid() { return pcid; } public String getPCBrand() { return pcBrand; } //Как видим внедренный admin будет //использован в объекте класса ServerPC //(то есть в бине ServerPC) для вывода //сообщения “Я администратор!” public String getAdminMessage() { return admin.adminMessage(); } }

Конфигурация бинов

Давайте же сконфигурируем наши первые два бина на основе тех классов, которые мы написали. Один бин будет внедряться в другой с помощью конструктора.

Конфигурация бинов происходит в xml файле. Название может быть любым, но принято называть applicationContext.xml.

Бин – это объект, который будет создаваться на основе конфигураций заданных в этом xml файле при создании объекта BeanFactory.

applicationContext.xml:


Создание и получение бинов в Java программе.

Давайте же теперь создадим класс сервлета, в котором создадим объект BeanFactory, который создаст нам бины, которые мы определяли выше для данного класса сервлета.

Пример программы:

import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import java.io.*; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.someclasses.ServerPC; @WebServlet(“/springservlet”) public class SpringServlet extends HttpServlet{ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //с помощью ClassPathXmlApplicationContext //(одна из реализаций BeanFactory) извлекаем //конфигурацию из applicationContext.xml ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( “applicationContext.xml”); //При создании объекта BeanFactory, //то есть context на основе файла, в котором //мы конфигурировали бины, создаются эти бины //и они хранятся в этом context. //И теперь мы можем извлечь созданные бины //из этого context с помощью метода getBean. //При этом указываем id бина и его класс либо //интерфейс, который реализует класс бина. ServerPC serverpc = context.getBean(“serverPCBean”,ServerPC.class); //Теперь пускай админ за компьютером //скажет “I’m an administrator!” resp.getWriter().write(serverpc.getAdminMessage()); } }

Проверка работы приложения

Теперь проверим скажет ли администратор “I’m an administrator!”.

Компилируем Java файлики. Файл сервлета при этом компилируем с использованием jar файлов спринг:

Запускаем Tomcat и открываем страницу сервлета по пути /springservlet :

Как видим, сказал. Из этого можно сделать вывод что объект, то есть бин класса Administrator внедрен в бин класса ServerPC, так как мы помним, что строку I’m an administrator возвращает метод именно класса Administrator и если бы в объекте serverpc не было объекта класса Administrator, то метод getAdminMessage объекта serverpc вернул бы ошибку.

Search Icon

При этом, заметьте, что в классе сервлета мы не создавали объектов и не внедряли их никуда, это сделала за нас BeanFactory и в итоге наш Java код не замусорен созданиями объектов и внедрениями, а их может быть довольно много в большом приложении, все определения и внедрения бинов вынесены в applicationContext.xml.