[Рекомендуемая коллекция] Примечания к аннотации Spring, обобщенные Ali P7, регистрация компонентов четко объяснена

Java

Строительство окружающей среды

Способ аннотирования заключается во внедрении компонентов путем настройки классов. Внедрение аннотаций проще, чем внедрение XML. Внедрение аннотаций также требует добавления пакета spring-context на основе первого, что также является широко используемым методом в реальной разработке.

Подготовьте необходимые пакеты Jar

Регистрация аннотированных компонентов Spring

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

@ComponentScan и @Configurable

Оригинальный xml-способ

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	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.xsd
		http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
	<!-- 要扫描的包 -->
	<context:component-scan base-package="model"></context:component-scan>
</beans>

Использовать класс конфигурации@Configurable помечает класс как класс конфигурации в Spring, а @ComponentScan("model") указывает параметры, которые должны быть просканированы для класса конфигурации.

package config;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.ComponentScan;
import model.Product;

/**
 * @Configurable: 该注解是标注该类是配置类
 * @ComponentScan:配置要扫描的包
 * @author GaoYang
 */
@Configurable
@ComponentScan("model")
public class MainConfig {

}

@Component

Используя эту аннотацию, вы можете зарегистрировать объект Java @Component в Ioc-контейнере.Если аннотация @Component присваивает свойство, оно должно быть присвоено свойству с аннотацией @Value.

/**
	@Componnt可以指定该对象的id,也可以不用指定
	默认id为该类的类名首字母小写
 */
@Component("students")
public class Student {
	@Value("01")
	private int sid;
	@Value("侯宁宁")
	private String name;
	@Value("男")
	private String sex;

класс конфигурации

/**
 * @Configurable: 该注解是标注该类是配置类
 * @ComponentScan:配置要扫描的包
 * @author GaoYang
 */
@Configurable
@ComponentScan("model")
public class MainConfig {

}

Внедрение с использованием @Configuration

@Component("students")
public class Student {
	@Value("01")
	private int sid;
	@Value("侯宁宁")
	private String name;
	@Value("男")
	private String sex;

	public Student() {
		super();
	}
	public Student(int sid, String name, String sex) {
		super();
		this.sid = sid;
		this.name = name;
		this.sex = sex;
	}
	public int getSid() {
		return sid;
	}
	public void setSid(int sid) {
		this.sid = sid;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getSex() {
		return sex;
	}
	public void setSex(String sex) {
		this.sex = sex;
	}
	@Override
	public String toString() {
		return "Student [sid=" + sid + ", name=" + name + ", sex=" + sex + "]";
	}

}

контрольная работа

@Bean

Используя аннотацию @Bean, мы можем аннотировать метод создания объекта в нашем классе регистрации spring.Мы можем создать объект через метод, который возвращает значение объекта, и присвоить значения свойствам объекта через метод конструктор.

// 配置类
@Configurable
@ComponentScan("model")
public class MainConfig {
	// 默认id为方法名
	@Bean
	public Product product1() {
		return new Product("张三","hashd",1);
	}
	// 可以指定id
	@Bean("product2")
	public Product product2() {
		return new Product("张三","hashd",1);
	}

}

Объект Java-Bean

public class Product {
	private String name;
	private String price;
	private int num;
	public Product() {
		super();
	}
	public Product(String name, String price, int num) {
		super();
		this.name = name;
		this.price = price;
		this.num = num;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getPrice() {
		return price;
	}
	public void setPrice(String price) {
		this.price = price;
	}
	public int getNum() {
		return num;
	}
	public void setNum(int num) {
		this.num = num;
	}
	@Override
	public String toString() {
		return "Product [name=" + name + ", price=" + price + ", num=" + num + "]";
	}

}

контрольная работа

@TypeFilter

Аннотация @TypeFilter Это фильтровать некоторые ресурсы, задавая условия, мы можем фильтровать некоторые ресурсы и предотвращать их загрузку в контейнер ioc. Его использование должно использоваться в аннотации @ComponentScan. Значение передается через параметр excludeFilters. excludeFilters — это массив, и может быть установлено несколько @TypeFilters.

Синтаксис @TypeFilter

@Configurable
@ComponentScan(value = "model",excludeFilters = {
		// FilterType.ANNOTATION是通过注解的形式进行过滤
		@Filter(type = FilterType.ANNOTATION,classes = {Controller.class}),

		// FilterType.ASSIGNABLE_TYPE 是通过给定的类型
		@Filter(type = FilterType.ASSIGNABLE_TYPE,classes = {Product.class}),

		// FilterType.ASPECTJ 根据正则表达式
		@Filter(type = FilterType.ASPECTJ,classes = {""}),

		// FilterType.CUSTOM 使用自定义规则
		@Filter(type = FilterType.CUSTOM,classes = {TypeFilterImp.class})

})
public class MainConfig {
	// @Bean == <bean></bean>

}

Пользовательские правила @FilterType.CUSTOM

Чтобы использовать пользовательские правила, мы должны создать для него класс создания правил. Этот класс должен реализовать интерфейс TypeFilter и метод match. Фильтр будет загружаться в соответствии с возвращаемым значением метода match. Если условие выполнено, если оно ложно, оно не будет загружено!

/**
	 * MetadataReader: 读取到的当前正在扫描的信息
	 * MetadataReaderFactory:可以获取到其他任何类的信息
	 */
	@Override
	public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
		// 获取当前类注解的信息
		AnnotationMetadata mr = metadataReader.getAnnotationMetadata();
		// 获取当前正在扫描的类的信息
		ClassMetadata classMetadata = metadataReader.getClassMetadata();
		// 获取当前类的资源信息
		Resource resource =  metadataReader.getResource();
		// 获取当前类的名字
		String className = classMetadata.getClassName();
		System.out.println("----"+className);
		// contains包含“er”
		if(className.contains("er")) {
			return true;
		}
		return false;
	}

}

@Scope

Объект, созданный Spring, по умолчанию является синглтоном, который описывается @Scope, то есть scope=«singleton».Кроме того, область действия также имеет область действия прототипа, запроса, сеанса и глобального сеанса.

Роль каждой сферы

  • Шаблон singleton singleton имеет один и только один экземпляр в глобальном масштабе. (по умолчанию)
  • Режим прототипа прототипа, каждый раз, когда вы получаете боб, будет новый экземпляр.
  • request указывает, что новый bean-компонент будет создан для каждого HTTP-запроса, и bean-компонент действителен только в рамках текущего HTTP-запроса, настройте экземпляр: Когда используются запрос, сеанс и глобальный сеанс, в файле web.xml, который инициализирует сеть, необходимо выполнить следующую конфигурацию: Если вы используете веб-контейнер Servlet 2.4 и выше, вам нужно всего лишь добавить следующий ContextListener в файл объявления XML web.xml веб-приложения:
<web-app>
 ...
	<listener>
		<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
	</listener>
 ...
</web-app>

  • Область сеанса означает, что для каждого HTTP-запроса будет создаваться новый компонент, и этот компонент действителен только в текущем HTTP-сеансе.
  • глобальная область сеанса похожа на стандартную область сеанса HTTP, но имеет смысл только в веб-приложении с портлетом. Спецификация портлета определяет концепцию глобального сеанса, который состоит из всех различных портлетов, совместно используемых веб-приложением с портлетами. В области, определенной глобальным компонентом сеанса, определяется область действия жизненного цикла глобального сеанса портлета. Если вы используете глобальную область сеанса в сети для идентификации компонента, сеть будет автоматически использоваться как тип сеанса.

Презентация кейса

singleton

@Configurable
@ComponentScan("model")
public class MainConfig {
   /**
    * @Scope
    * prototype: 多实例的  @Scope("prototype")
    * singleton: 单实例的  @Scope("person")
    * request: 一次请求创建一个实例
    * session: 同一个session创建一个实例
    * @return
    */
   @Scope("singleton")
   @Bean
   public Product product() {
   	System.out.println("该实例已被创建");
   	return new Product("张三","hashd",1);
   }
}

тестовый код

public class text {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
		System.out.println("Ioc容器已创建完成!");
		Product bean1 = applicationContext.getBean(Product.class);
		Product bean2 = applicationContext.getBean(Product.class);
		System.out.println(bean1== bean2);

	}
}

Как видно из рисунка ниже, bean1 == bean2

Layz-bean

Загрузка @Layz Lai в основном предназначена для одноэлементного режима. Когда контейнер ioc инициализируется в одноэлементном режиме, объект bean-компонента вводится в контейнер. Аннотация @Layz может заставить контейнер не регистрировать контейнер при его создании, а ждать, пока первый объект bean будет зарегистрирован только тогда, когда он вызывается в следующий раз. На данный момент созданный объект все еще является одноэлементным шаблоном!

использовать синтаксис

// 配置类
@Configurable
@ComponentScan("model")
public class MainConfig {
	/**
	 * 懒加载:
	 * 		针对的是单实例的bean,默认在容器启动的时候创建对象
	 * 		赖加载:容器启动时不创建对象,当第一次被调用时被创建
	 * 
	 */
	@Lazy
	@Bean
	public Product product() {
		System.out.println("该实例已被创建");
		return new Product("张三","hashd",1);
	}	

контрольная работа

@Conditional

Аннотация @Conditional регистрируется по заданным условиям.Мне нужно создать класс конфигурации для условий конфигурации.При выполнении условий будет выполнена регистрация, а при невыполнении условий регистрация не будет выполнена .

грамматика

класс конфигурации

@Configurable
public class MainConfig {

	@Conditional({winCondition.class})
	@Bean("wind")
	public Product wind() {
		System.out.println("该实例已被创建");
		return new Product("张三","wind",1);
}	

Класс условия должен реализовать интерфейс Condition и добавить его как реализованный метод!

public class winCondition implements Condition{

	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata arg1) {
		Environment environment = context.getEnvironment();
		// 获取当前操作系统的名字
		String property = environment.getProperty("os.name");
		if(property.contains("Windows")) {
			return true;
		}
		return false;
	}
}

кейс

Требуется зарегистрировать компоненты в соответствии с текущей операционной системой.

// 配置类
@Configurable
@Import(Hero.class)
public class MainConfig {
	// Windows系统
	@Conditional({winCondition.class})
	@Bean("wind")
	public Product wind() {
		System.out.println("该实例已被创建");
		return new Product("张三","wind",1);
	}
	// Linux系统  
	@Conditional({linuxCondition.class})
	@Bean("linux")
	public Product linux() {
		return new Product("李四","linux",2);

	}

}

Класс конфигурации условия

public class winCondition implements Condition{
	// Windows系统,返回true
	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata arg1) {
		Environment environment = context.getEnvironment();
		String property = environment.getProperty("os.name");
		if(property.contains("Windows")) {
			return true;
		}
		return false;
	}

}

public class linuxCondition implements Condition{
	/**
	 * ConditionContext: 判断条件能使用上下文环境
	 * AnnotatedTypeMetadata: 注释信息
	 */

	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		// 是否Linux系统
		// 1、能获取到ioc使用的bean工厂
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		// 2、获取类加载器
		ClassLoader clLoader = context.getClassLoader();
		// 3、获取当前环境信息
		  Environment environment = context.getEnvironment();
		  String property = environment.getProperty("os.name");

		// 5、bean注册类
		  BeanDefinitionRegistry registry = context.getRegistry();
		  if(property.contains("Linux")) {
			  return true;
		  }

		return false;
}

контрольная работа…

@import

  • @Import можно использовать только для классов. @Import добавляет экземпляры в контейнер Spring IOC посредством быстрого импорта.
  • IOC присоединиться к сосуду много способов Import Notes. Относительно очень кожаная, @ импортная аннотация может использоваться для импорта сторонних пакетов, конечно же, конечно, аннотация @Bean может быть, но как можно быстро импортировать @import
  • Есть три варианта использования аннотации @Import.

Первое использование: заполните массив классов напрямую

Заполните соответствующий массив классов напрямую, массив классов может иметь 0 или более. Соответствующие импортированные bean-компоненты будут добавлены в контейнер Spring, а имя bean-компонента в контейнере — это полное имя класса класса, например com.yc.

@Import({ 类名.class , 类名.class... })
public class TestDemo {

}

Второе использование: метод ImportSelector [Ключевые моменты]

Предпосылка этого метода заключается в том, что класс должен реализовать интерфейс ImportSelector.Если я хочу использовать этот метод, целевым объектом является класс Myclass.Анализ выглядит следующим образом: Создайте класс Myclass и реализуйте интерфейс ImportSelector

public class Myclass implements ImportSelector {
//既然是接口肯定要实现这个接口的方法
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        return new String[0];
    }
}
// 分析实现接口的selectImports方法中的:

// 1、返回值: 就是我们实际上要导入到容器中的组件全类名【重点 】
// 2、参数: AnnotationMetadata表示当前被@Import注解给标注的所有注解信息【不是重点】
// 需要注意的是selectImports方法可以返回空数组但是不能返回null,否则会报空指针异常!

После приведенного выше анализа конкретные этапы использования следующие: Шаг 1: Создайте класс MyClass и реализуйте интерфейс ImportSelector, чтобы добавить полное имя класса в возвращаемое значение.

public class Myclass implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        return new String[]{"com.yc.Test.TestDemo3"};
    }
}

Шаг 2: Напишите класс TestDemo и пометили классы MyClass, используя режим импорта.

@Import({TestDemo2.class,Myclass.class})
public class TestDemo {
        @Bean
        public AccountDao2 accountDao2(){
            return new AccountDao2();
        }

}

Шаг 3: Напишите тестовый класс компонента в контейнере печати

**
 * 打印容器中的组件测试
 */
public class AnnotationTestDemo {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(TestDemo.class);  //这里的参数代表要做操作的类

        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String name : beanDefinitionNames){
            System.out.println(name);
        }

    }
}

Третье использование: метод ImportBeanDefinitionRegistrar

Это также интерфейс, аналогичный второму использованию ImportSelector, с подобием 80%, но это использование более настраиваемое, как показано ниже:

public class Myclass2 implements ImportBeanDefinitionRegistrar {
//该实现方法默认为空
    @Override
    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {

    }
}
// 参数分析:

// 第一个参数:annotationMetadata 和之前的ImportSelector参数一样都是表示当前被@Import注解给标注的所有注解信息
// 第二个参数表示用于注册定义一个bean

Шаг 2: Напишите код для настройки зарегистрированных bean-компонентов

public class Myclass2 implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
        //指定bean定义信息(包括bean的类型、作用域...)
        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(TestDemo4.class);
        //注册一个bean指定bean名字(id)
        beanDefinitionRegistry.registerBeanDefinition("TestDemo4444",rootBeanDefinition);
    }
}

Шаг 3: Напишите класс TestDemo и пометьте класс Myclass2 с помощью метода ImportBeanDefinitionRegistrar.

@Import({TestDemo2.class,Myclass.class,Myclass2.class})
public class TestDemo {

        @Bean
        public AccountDao2 accountDao222(){
            return new AccountDao2();
        }

}

@FactoryBean

Напишите класс конфигурации

// 标记这是一个Spring配置类
@Configuration
public class SpringConfiguration {
    // 如果没有@Bean注解,则注入到容器中的id就是方法名(也就是myFactoryBean),但是如果显示的给了值,那么注入到容器中的就是factoryBean
    @Bean("factoryBean")
    public MyFactoryBean myFactoryBean(){
        return new MyFactoryBean();
    }
}

тестовый класс

public class SpringDemo {

    @Test
    public void springTest01() throws Exception {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfiguration.class);
        // 容器中获取的Bean,实际上就是工厂Bean(MyFactoryBean通过getObject()方法返回的对象)
        Object factoryBean01 = context.getBean("factoryBean");
        System.out.println("实际上注入到容器中的类型是:" + factoryBean01.getClass());

        Object factoryBean02 = context.getBean("factoryBean");
        System.out.println("注入到容器内的对象是否是单例:" + (factoryBean01 == factoryBean02));

        Object factoryBean03 = context.getBean("&factoryBean");
        System.out.println("如果想获取到MyFactoryBean的对象,使用&前缀:" + factoryBean03);

        // 输出打印Spring中的所有Bean名称
        String[] beanDefinitionNames = context.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName);
        }
    }
}

Наконец

Спасибо, что прочитали это. Пожалуйста, исправьте меня, если в статье есть какие-либо недостатки. Если вы считаете, что статья полезна для вас, не забудьте поставить мне лайк. Я буду делиться техническими статьями или отраслевой информацией о Java каждый день. Добро пожаловать Всем подписаться и переслать статью!