Управление bean-компонентами spring при конфигурировании на основе java

Содержание

Введение в аннотации @Configuration и @Bean

В идеале вы бы определили bean-компоненты в XML-файле, который содержит конфигурацию контекста приложения. Нижеследующий программный код показывает XML-файл контекста приложения с определениями bean-компонентов для сценария create course:


Листинг 1. XML-файл с определениями bean-компонентов
<beans>
	<bean id="course" class="demo.Course">
		<property name="module" ref="module"/>
  	</bean>
	
	<bean id="module" class="demo.Module">
		<property name="assignment" ref="assignment"/>
  	</bean>
	
	<bean id="assignment" class="demo.Assignment" />
</beans>

Представленный выше XML-файл — это то, что вы обычно пишете для конфигурирования bean-компонентов в среде разработки Spring. Данный XML-файл определяет bean-компонент , который ссылается на bean-компонент , а bean-компонент ссылается на bean-компонент . Давайте отставим в сторону этот XML-файл и напишем вместо него эквивалентный программный код Java. Мы определим указанные выше bean-компоненты с использованием конфигурирования на основе Java. XML-файл мы заменим классом Java, который теперь будет играть роль платформы для конфигурирования bean-компонентов. Назовем этот класс . Следующий фрагмент кода показывает класс .

Листинг 2. Класс конфигурации AppContext, содержащий определения bean-компонентов
@Configuration
public class AppContext {
	@Bean
	public Course course() {
		Course course = new Course();
		course.setModule(module());
		return course;
	}

	@Bean
	public Module module() {
		Module module = new Module();
		module.setAssignment(assignment());
		return module;
	}

	@Bean
	public Assignment assignment() {
		return new Assignment();
	}
}

Как видно из приведенного выше программного кода, теперь bean-компоненты определены программными средствами в рамках конфигурирования на основе Java. Теперь класс представляет собой класс конфигурации, совсем как XML-файл. Это достигается путем использования аннотации , которая размещается над классом. Она сообщает контейнеру Spring, что это класс конфигурации, содержащий определения и зависимости bean-компонентов. Для определения bean-компонентов используется аннотация . Данная аннотация размещается над методом, который создает экземпляр bean-компонента и устанавливает зависимость. По умолчанию имя этого метода совпадает с идентификатором или именем bean-компонента. В результате вызова метода возвращается bean-компонент, зарегистрированный в контексте приложения Spring. Для установления зависимостей используются методы setter bean-компонента, и контейнер будет вызывать их для «прокладки» связей. Конфигурирование на основе Java также можно рассматривать как конфигурирование на основе аннотаций.

Введение

Spring обеспечивает решения многих задач, с которыми сталкиваются Java-разработчики и организации, которые хотят создать информационную систему, основанную на платформе Java. Из-за широкой функциональности трудно определить наиболее значимые структурные элементы, из которых он состоит

Spring не всецело связан с платформой Java Enterprise, несмотря на его масштабную интеграцию с ней, что является важной причиной его популярности.

Spring, вероятно, наиболее известен как источник расширений (features), нужных для эффективной разработки сложных бизнес-приложений вне тяжеловесных программных моделей, которые исторически были доминирующими в промышленности. Ещё одно его достоинство в том, что он ввел ранее неиспользуемые функциональные возможности в сегодняшние господствующие методы разработки, даже вне платформы Java.

Этот фреймворк предлагает последовательную модель и делает её применимой к большинству типов приложений, которые уже созданы на основе платформы Java. Считается, что Spring реализует модель разработки, основанную на лучших стандартах индустрии, и делает её доступной во многих областях Java.

Example

Let us have working Eclipse IDE in place and follow the following steps to create a Spring application −

Steps Description
1 Create a project with a name SpringExample and create a package com.tutorialspoint under the src folder in the created project.
2 Add required Spring libraries using Add External JARs option as explained in the Spring Hello World Example chapter.
3 Create Java classes TextEditor, SpellChecker and MainApp under the com.tutorialspoint package.
4 Create Beans configuration file Beans.xml under the src folder.
5 The final step is to create the content of all the Java files and Bean Configuration file and run the application as explained below.

Here is the content of TextEditor.java file −

package com.tutorialspoint;

public class TextEditor {
   private SpellChecker spellChecker;
   
   // a setter method to inject the dependency.
   public void setSpellChecker(SpellChecker spellChecker) {
      System.out.println("Inside setSpellChecker." );
      this.spellChecker = spellChecker;
   }
   
   // a getter method to return spellChecker
   public SpellChecker getSpellChecker() {
      return spellChecker;
   }
   public void spellCheck() {
      spellChecker.checkSpelling();
   }
}

Following is the content of another dependent class file SpellChecker.java

package com.tutorialspoint;

public class SpellChecker {
   public SpellChecker(){
      System.out.println("Inside SpellChecker constructor." );
   }
   public void checkSpelling(){
      System.out.println("Inside checkSpelling." );
   }
}

Following is the content of the MainApp.java file −

package com.tutorialspoint;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
   public static void main(String[] args) {
      ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
      TextEditor te = (TextEditor) context.getBean("textEditor");
      te.spellCheck();
   }
}

Following is the configuration file Beans.xml which has configuration for the setter-based injection but using inner beans

<?xml version = "1.0" encoding = "UTF-8"?>

<beans xmlns = "http://www.springframework.org/schema/beans"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation = "http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <!-- Definition for textEditor bean using inner bean -->
   <bean id = "textEditor" class = "com.tutorialspoint.TextEditor">
      <property name = "spellChecker">
         <bean id = "spellChecker" class = "com.tutorialspoint.SpellChecker"/>
      </property>
   </bean>

</beans>

Once you are done creating the source and bean configuration files, let us run the application. If everything is fine with your application, it will print the following message −

Inside SpellChecker constructor.
Inside setSpellChecker.
Inside checkSpelling.

Previous Page Print Page

Next Page  

@Qualifier Annotation

By using the @Qualifier annotation, we can eliminate the issue of which bean needs to be injected.

Let’s revisit our previous example and see how we solve the problem by including the @Qualifier annotation to indicate which bean we want to use:

By including the @Qualifier annotation together with the name of the specific implementation we want to use – in this example, Foo – we can avoid ambiguity when Spring finds multiple beans of the same type.

We need to take into consideration that the qualifier name to be used is the one declared in the @Component annotation.

Note that we could’ve also used the @Qualifier annotation on the Formatter implementing classes, instead of specifying the names in their @Component annotations, to obtain the same effect:

Injecting Bean References

Let’s look at an example where we inject bean references as elements of the collection.

First, let’s create the bean:

And add a List of BaeldungBean as a property to the CollectionsBean class:

Next, we add the Java configuration factory methods for each BaeldungBean element:

The Spring container injects the individual beans of the BaeldungBean type into one collection.

To test this, we invoke the collectionsBean.printBeanList() method. The output shows the bean names as list elements:

Now, let’s consider a scenario when there is not a BaeldungBean. If there isn’t a BaeldungBean registered in the application context, Spring will throw an exception because the required dependency is missing.

We can use @Autowired(required = false) to mark the dependency as optional. Instead of throwing an exception, the beanList won’t be initialized and its value will stay null.

If we need an empty list instead of null, we can initialize beanList with a new ArrayList:

5.1. Using @Order to Sort Beans

We can specify the order of the beans while injecting into the collection.

For that purpose, we use the @Order annotation and specify the index:

Spring container first will inject the bean with the name “Harry”, as it has the lowest order value.

It will then inject the “John”, and finally, the “Adam” bean:

Learn more about @Order in this guide.

5.2. Using @Qualifier to Select Beans

We can use the @Qualifier to select the beans to be injected into the specific collection that matches the @Qualifier name.


Here’s how we use it for the injection point:

Then, we mark with the same @Qualifier the beans that we want to inject into the List:

In this example, we specify that the bean with the name “John” will be injected into the List named “CollectionsBean”. The results we test here:

From the output, we see that our collection has only one element:

The getBean() APIs

BeanFactory provides five different signatures of the getBean() method that we’re going to examine in the following subsections.

3.1. Retrieving Bean by Name

Let’s see how we can retrieve a Lion bean instance using its name:

In this variant, we provide a name, and in return, we get an instance of Object class if a bean with the given name exists in the application context. Otherwise, both this and all other implementations throw NoSuchBeanDefinitionException if the bean lookup fails.

The main disadvantage is that after retrieving the bean, we have to cast it to the desired type. This may produce another exception if the returned bean has a different type than we expected.

Suppose we try to get a Tiger using the name “lion”.  When we cast the result to Tiger, it will throw a ClassCastException:

3.2. Retrieving Bean by Name and Type

Here we need to specify both the name and type of the requested bean:

Compared to the previous method, this one is safer because we get the information about type mismatch instantly:

3.3. Retrieving Bean by Type

With the third variant of getBean(), it is enough to specify only the bean type:

In this case, we need to pay special attention to a potentially ambiguous outcome:

In the example above, because both Lion and Tiger implement the Animal interface, merely specifying type isn’t enough to unambiguously determine the result. Therefore, we get a NoUniqueBeanDefinitionException.

3.4. Retrieving Bean by Name with Constructor Parameters

In addition to the bean name, we can also pass constructor parameters:

This method is a bit different because it only applies to beans with prototype scope.

In the case of singletons, we’re going to get a BeanDefinitionStoreException.

Because a prototype bean will return a newly created instance every time it’s requested from the application container, we can provide constructor parameters on-the-fly when invoking getBean():

As we can see, each Tiger gets a different name according to what we specified as a second parameter when requesting the bean.

3.5. Retrieving Bean by Type With Constructor Parameters

This method is analogous to the last one, but we need to pass the type instead of the name as the first argument:

Similar to retrieving a bean by name with constructor parameters, this method only applies to beans with prototype scope.

Реализация обратных вызовов для извещения о событиях жизненного цикла и области действия bean-компонента

Обратные вызовы для извещения о событиях жизненного цикла

С помощью конфигурирования на основе Java также можно управлять жизненным циклом bean-компонентов. Аннотация поддерживает два атрибута ( и ), которые могут использоваться для определения методов жизненного цикла. Методы жизненного цикла вызываются контейнером при создании экземпляра bean-компонента и перед его уничтожением. Методы жизненного цикла также называются методами обратного вызова, поскольку они вызываются контейнером. Bean-компонент, зарегистрированный с помощью аннотации , также поддерживает стандартные аннотации и как часть JSR-250. Если вы используете для определения bean-компонентов XML-подход, то для определения методов обратного вызова событий жизненного цикла вы будете использовать элемент <bean>. В приведенном ниже фрагменте программного кода показано, как обычно определяются обратные вызовы с использованием элемента <bean> в XML-конфигурации.

Листинг 7. Использование XML-подхода для обратных вызовов событий жизненного цикла
<bean id="course" class="demo.Course" init-method="setup" destroy-method="cleanup" >
	<property name="module" ref="module"/>
</bean>

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

@Configuration
public class AppContext {
	@Bean(initMethod = "setup", destroyMethod = "cleanup")
	public Course course() {
		Course course = new Course();
		course.setModule(module());
		return course;
	}

	@Bean(initMethod = "setup", destroyMethod = "cleanup")
	public Module module() {
		Module module = new Module();
		module.setAssignment(assignment());
		return module;
	}
	
	...
}		
public class Course {

	private Module module;
	private String name;
	
	public Course() {
	}
	
	public void setup() {
		this.name = "M100 Pythagoras Theorems"
	}
	
	public void setModule(Module module) {
		this.module = module;
	}
	
	public void cleanup() {
		module = null;
	}
}

В приведенном выше фрагменте программного кода мы снова возвращаемся к классу конфигурации . Теперь аннотация имеет два дополнительных атрибута: и . Они определяют методы жизненного цикла и . Эти методы реализуются в зарегистрированном bean-компоненте и, в конечном счете, вызываются контейнером при инициализации bean-компонента и перед его уничтожением. Bean-компонент , рассматриваемый здесь в качестве примера, иллюстрирует реализацию методов жизненного цикла. Реализованными методами являются и . Аналогичным образом эти методы также можно реализовать в bean-компонентах и .

Области действия bean-компонентов

Область действия bean-компонента может быть определена с помощью аннотации . В XML для этого было принято указывать атрибут области действия в элементе <bean>.

Листинг 9. Использование XML-подхода для определения области действия bean-компонента
<bean id="course" class="demo.Course" scope="prototype" >
	<property name="module" ref="module"/>
</bean>

Нижеследующий фрагмент программного кода показывает порядок определения области действия bean-компонента при конфигурации на основе Java.

@Configuration
public class AppContext {
	@Bean(initMethod = "setup", destroyMethod = "cleanup")
	@Scope("prototype")
	public Course course() {
		Course course = new Course();
		course.setModule(module());
		return course;
	}
	...
}

Как видно из приведенного выше программного кода, определить область действия bean-компонента в классе конфигурации Java достаточно просто. Указанный выше класс конфигурации определяет область действия prototype для bean-компонента с использованием аннотации . Область действия по умолчанию —singleton.

Java-конфигурирование позволяет делать множество вещей. В этой статье мы затронули лишь основы. Использование конфигурирования на основе Java не предоставляет никаких существенных преимуществ, это просто альтернатива XML-подходу, предлагаемому средой разработки Spring. Это прекрасный выбор для тех, кто предпочитает не использовать XML в своей среде разработки. Недостатком, разумеется, является то, что при внесении любых изменений в конфигурацию в классе Java вам потребуется перекомпилировать приложение.

  • Оригинал статьи: Spring bean management using Java configuration.
  • Разработка Web-сервисов с использованием Apache CXF и Aegis : научитесь разрабатывать Web-сервисы с использованием привязки данных в CXF и Aegis.
  • Разработка и реализация Web-сервисов POJO с использованием Spring и Apache CXF, часть 1: Введение в создание Web-сервисов с использованием CXF и Spring.
  • Разработка и реализация Web-сервисов POJO с использованием Spring и Apache CXF, часть 2: Создание Web-сервиса RESTful.

Destruction callbacks

The org.springframework.beans.factory.DisposableBean interface specifies a single method −

void destroy() throws Exception;

Thus, you can simply implement the above interface and finalization work can be done inside destroy() method as follows −

public class ExampleBean implements DisposableBean {
   public void destroy() {
      // do some destruction work
   }
}

In the case of XML-based configuration metadata, you can use the destroy-method attribute to specify the name of the method that has a void no-argument signature. For example −

<bean id = "exampleBean" class = "examples.ExampleBean" destroy-method = "destroy"/>

Following is the class definition −

public class ExampleBean {
   public void destroy() {
      // do some destruction work
   }
}

If you are using Spring’s IoC container in a non-web application environment; for example, in a rich client desktop environment, you register a shutdown hook with the JVM. Doing so ensures a graceful shutdown and calls the relevant destroy methods on your singleton beans so that all resources are released.

It is recommended that you do not use the InitializingBean or DisposableBean callbacks, because XML configuration gives much flexibility in terms of naming your method.

Example

Let us have a working Eclipse IDE in place and take the following steps to create a Spring application −

Steps Description
1 Create a project with a name SpringExample and create a package com.tutorialspoint under the src folder in the created project.
2 Add required Spring libraries using Add External JARs option as explained in the Spring Hello World Example chapter.
3 Create Java classes HelloWorld and MainApp under the com.tutorialspoint package.
4 Create Beans configuration file Beans.xml under the src folder.
5 The final step is to create the content of all the Java files and Bean Configuration file and run the application as explained below.

Here is the content of HelloWorld.java file −

package com.tutorialspoint;

public class HelloWorld {
   private String message;

   public void setMessage(String message){
      this.message = message;
   }
   public void getMessage(){
      System.out.println("Your Message : " + message);
   }
   public void init(){
      System.out.println("Bean is going through init.");
   }
   public void destroy() {
      System.out.println("Bean will destroy now.");
   }
}

Following is the content of the MainApp.java file. Here you need to register a shutdown hook registerShutdownHook() method that is declared on the AbstractApplicationContext class. This will ensure a graceful shutdown and call the relevant destroy methods.

package com.tutorialspoint;

import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
   public static void main(String[] args) {
      AbstractApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");

      HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
      obj.getMessage();
      context.registerShutdownHook();
   }
}

Following is the configuration file Beans.xml required for init and destroy methods −

<?xml version = "1.0" encoding = "UTF-8"?>

<beans xmlns = "http://www.springframework.org/schema/beans"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation = "http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean id = "helloWorld" class = "com.tutorialspoint.HelloWorld" init-method = "init" 
      destroy-method = "destroy">
      <property name = "message" value = "Hello World!"/>
   </bean>

</beans>

Once you are done creating the source and bean configuration files, let us run the application. If everything is fine with your application, it will print the following message −

Bean is going through init.
Your Message : Hello World!
Bean will destroy now.

The singleton scope

If a scope is set to singleton, the Spring IoC container creates exactly one instance of the object defined by that bean definition. This single instance is stored in a cache of such singleton beans, and all subsequent requests and references for that named bean return the cached object.

The default scope is always singleton. However, when you need one and only one instance of a bean, you can set the scope property to singleton in the bean configuration file, as shown in the following code snippet −

<!-- A bean definition with singleton scope -->
<bean id = "..." class = "..." scope = "singleton">
   <!-- collaborators and configuration for this bean go here -->
</bean>

Example

Let us have a working Eclipse IDE in place and take the following steps to create a Spring application −

Steps Description
1 Create a project with a name SpringExample and create a package com.tutorialspoint under the src folder in the created project.
2 Add required Spring libraries using Add External JARs option as explained in the Spring Hello World Example chapter.
3 Create Java classes HelloWorld and MainApp under the com.tutorialspoint package.
4 Create Beans configuration file Beans.xml under the src folder.
5 The final step is to create the content of all the Java files and Bean Configuration file and run the application as explained below.

Here is the content of HelloWorld.java file −

package com.tutorialspoint;

public class HelloWorld {
   private String message;

   public void setMessage(String message){
      this.message  = message;
   }
   public void getMessage(){
      System.out.println("Your Message : " + message);
   }
}

Following is the content of the MainApp.java file −

package com.tutorialspoint;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
   public static void main(String[] args) {
      ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
      HelloWorld objA = (HelloWorld) context.getBean("helloWorld");

      objA.setMessage("I'm object A");
      objA.getMessage();

      HelloWorld objB = (HelloWorld) context.getBean("helloWorld");
      objB.getMessage();
   }
}

Following is the configuration file Beans.xml required for singleton scope −

<?xml version = "1.0" encoding = "UTF-8"?>

<beans xmlns = "http://www.springframework.org/schema/beans"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation = "http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean id = "helloWorld" class = "com.tutorialspoint.HelloWorld" scope = "singleton">
   </bean>

</beans>

Once you are done creating the source and bean configuration files, let us run the application. If everything is fine with your application, it will print the following message −

Your Message : I'm object A
Your Message : I'm object A

Scope у Spring Bean

В Spring предусмотрены различные области времени действия бинов:

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

Следует осторожно использовать публичные свойства класса, т.к. они не будут потокобезопасными. prototype — создается новый экземпляр при каждом запросе. request — аналогичен prototype, но название служит пояснением к использованию бина в веб приложении

Создается новый экземпляр при каждом HTTP request. session — новый бин создается в контейнере при каждой новой HTTPS (HyperText Transfer Protocol Secure) сессии. global-session: используется для создания глобальных бинов на уровне сессии для Portlet приложений.

Possible Solutions

Depending on our configuration, Spring Beans have default names unless we set them explicitly.

Therefore, the first possible solution is to rename our beans.

There are some common ways to set bean names in Spring.

6.1. Changing Method Names

By default, Spring takes the name of the annotated methods as bean names.

Therefore, if we have beans defined in a configuration class, like our example, then simply changing the method names will prevent the BeanDefinitionOverrideException:

6.2. @Bean Annotation

Spring’s @Bean annotation is a very common way of defining a bean.

Thus, another option is to set the name property of @Bean annotation:

6.3. Stereotype Annotations

Another way to define a bean is with stereotype annotations. With Spring’s @ComponentScan feature enabled, we can define our bean names at the class level using the @Component annotation:

6.4. Beans Coming From 3rd Party Libraries

In some cases, it’s possible to encounter a name conflict caused by beans originating from 3rd party spring-supported libraries.

When this happens, we should attempt to identify which conflicting bean belongs to our application, to determine if any of the above solutions can be used.

However, if we are unable to alter any of the bean definitions, then configuring Spring Boot to allow bean overriding can be a workaround.

To enable bean overriding, let’s set the spring.main.allow-bean-definition-overriding property to true in our application.properties file:

By doing this, we are telling Spring Boot to allow bean overriding without any change to bean definitions.


As a final notice, we should be aware that it is difficult to guess which bean will have priority because the bean creation order is determined by dependency relationships mostly influenced in runtime. Therefore, allowing bean overriding can produce unexpected behavior unless we know the dependency hierarchy of our beans well enough.

The Basics of Factory Beans

2.1. Implement a FactoryBean

Let’s look at the FactoryBean interface first:

Let’s discuss the three methods:

  • getObject() – returns an object produced by the factory, and this is the object that will be used by Spring container
  • getObjectType() – returns the type of object that this FactoryBean produces
  • isSingleton() – denotes if the object produced by this FactoryBean is a singleton

Now, let’s implement an example FactoryBean. We’ll implement a ToolFactory which produces objects of the type Tool:

The ToolFactory itself:

As we can see, the ToolFactory is a FactoryBean, which can produce Tool objects.

2.2. Use FactoryBean With XML-based Configuration

Let’s now have a look at how to use our ToolFactory.

We’ll start constructing a tool with XML-based configuration – factorybean-spring-ctx.xml:

Next, we can test if the Tool object is injected correctly:

The test result shows we manage to inject the tool object produced by the ToolFactory with the properties we configured in the factorybean-spring-ctx.xml.

The test result also shows that the Spring container uses the object produced by the FactoryBean instead of itself for dependency injection.

Although the Spring container uses the FactoryBean‘s getObject() method’s return value as the bean, you can also use the FactoryBean itself.

To access the FactoryBean, you just need to add a “&” before the bean name.

Let’s try getting the factory bean and its factoryId property:

2.3. Use FactoryBean With Java-based Configuration

Use FactoryBean with Java-based configuration is a little different with XML-based configuration, you have to call the FactoryBean‘s getObject() method explicitly.

Let’s convert the example in the previous subsection into a Java-based configuration example:

Then, we test if the Tool object is injected correctly:

The test result shows the similar effect as the previous XML-based configuration test.

Why to Learn Spring?

Spring is the most popular application development framework for enterprise Java. Millions of developers around the world use Spring Framework to create high performing, easily testable, and reusable code.

Spring framework is an open source Java platform. It was initially written by Rod Johnson and was first released under the Apache 2.0 license in June 2003.

Spring is lightweight when it comes to size and transparency. The basic version of Spring framework is around 2MB.

The core features of the Spring Framework can be used in developing any Java application, but there are extensions for building web applications on top of the Java EE platform. Spring framework targets to make J2EE development easier to use and promotes good programming practices by enabling a POJO-based programming model.

Injecting ApplicationContext

We can also inject the ApplicationContext directly into a bean.

To achieve this, either use the @Autowire annotation or implement the ApplicationContextAware interface:

Every time the getPrototypeBean() method is called, a new instance of PrototypeBean will be returned from the ApplicationContext.

However, this approach has serious disadvantages. It contradicts the principle of inversion of control, as we request the dependencies from the container directly.

Also, we fetch the prototype bean from the applicationContext within the SingletonAppcontextBean class. This means coupling the code to the Spring Framework.

DI/IoC

IoC (Inversion of Control) — инверсия управления. При использовании библиотеки вы сами прописываете в своем коде какой метод какого объекта вызвать, а в случает с фреймворками — чаще всего уже фреймворк будет вызывать в нужный ему момент тот код, который уже написали. То есть, тут уже не вы управляете процессом выполнения кода/программы, а фреймворк это делает за вас. Вы передали ему управление (инверсия управления).

Под DI(Dependency Injection) — внедрение зависимостей, это встраивание различных объектов в определённые классы.

public interface Music {

   void setSong(String songName);

   String getSong();

}

public class MusicPlayer {

   private Music music;       /*-----Слабая зависимость, так как реализовано через интерфейс.-----*/

   public MusicPlayer(Music music) {     /*-----Внедрение слабой зависимости посредством конструктора-----*/
     this.music = music;
   }

   public void playMusic() {
     System.out.println("Playing: " + music.getSong());
   }

}

Aspect, Advice, Pointcut, JointPoint и Advice Arguments в АОП

Существуют пункты, из которых состоит аспектно-ориентированное программирование:

  • Точка соединения (joinpoint) — это четко определенная точка во время выполнения приложения. Типовые примеры точек соединения включают обращение к методу, собственно Method Invocation, инициализацию класса и создание экземпляра объекта. Точки соединения являются ключевой концепцией АОП и определяют места в приложении, в которые можно вставлять дополнительную логику с использованием АОП.
  • Советы (advice). Фрагмент кода, который должен выполняться в отдельной точке соединения, представляет собой совет (advice). Существует несколько типов советов, среди которых перед, когда совет выполняется до точки соединения, и после, когда совет выполняется после точки соединения. В ООП совет принимает форму метода внутри класса.
  • Срез (pointcut) — это коллекция точек соединения, которая используется для определения ситуации, когда совет должен быть выполнен. Создавая срезы, вы получаете точный контроль над тем, как применять совет к компонентам приложения. Как упоминалось ранее, типичной точкой соединения является Method Invocation. А типичный срез представляет собой коллекцию всех точек соединения Method Invocation в отдельном классе. Часто между срезами можно установить сложные отношения, чтобы обеспечить дополнительные ограничения на то, когда будет выполнен совет.
  • Аспект (aspect) — это комбинация совета и срезов. Такая комбинация дает в результате определение логики, которая должна быть включена в приложение, и указание мест, где она должна выполняться.
  • Связывание (weaving) представляет собой процесс действительной вставки аспектов в определенную точку кода приложения. Для решений АОП времени компиляции это делается на этапе компиляции, обычно в виде дополнительного шага процесса сборки. Аналогично, для решений АОП времени выполнения связывание происходит динамически во время выполнения. В AspectJ поддерживается еще один механизм связывания под названием связывание во время загрузки (load-time weaving — LTW), который перехватывает лежащий в основе загрузчик классов JVM и обеспечивает связывание с байт-кодом, когда он загружается загрузчиком классов.
  • Цель (target) — это объект, поток выполнения которого изменяется каким-то процессом АОП. На целевой объект часто ссылаются как на объект, снабженный советом.
  • Введение (introduction) представляет собой процесс, посредством которого можно изменить структуру объекта за счет введения в него дополнительных методов или полей. Введение можно использовать для обеспечения реализации любым объектом определенного интерфейса без необходимости в том, чтобы класс этого объекта реализовывал такой интерфейс явно.

Default initialization and destroy methods

If you have too many beans having initialization and/or destroy methods with the same name, you don’t need to declare init-method and destroy-method on each individual bean. Instead, the framework provides the flexibility to configure such situation using default-init-method and default-destroy-method attributes on the <beans> element as follows −

<beans xmlns = "http://www.springframework.org/schema/beans"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation = "http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
   default-init-method = "init" 
   default-destroy-method = "destroy">

   <bean id = "..." class = "...">
      <!-- collaborators and configuration for this bean go here -->
   </bean>
   
</beans>

Previous Page Print Page

Next Page  

Жизненный цикл Spring Bean

Жизненный цикл Spring бина — время существования класса. Spring бины инициализируются при инициализации Spring контейнера и происходит внедрение всех зависимостей. Когда контейнер уничтожается, то уничтожается и всё содержимое. Если нам необходимо задать какое-либо действие при инициализации и уничтожении бина, то нужно воспользоваться методами init() и destroy(). Для этого можно использовать аннотации @PostConstruct и @PreDestroy().

@PostConstruct
    public void init(){
        System.out.println("Bean init method called");
    }
     
 
    @PreDestroy
    public void destroy(){
        System.out.println("Bean destroy method called");
    }

Или через xml конфигурацию:

<bean name="myBean" class="ru.javastudy.spring.MyBean"
        init-method="init" destroy-method="destroy">
    <property name="someProp" ref="someProp"></property>
</bean>

С этим читают