Поскольку я использовал Spring Boot, я использую его все время, и я больше не могу смотреть прямо на предыдущий код Spring.соглашение о конфигурацииКонцепция дизайна позволяет легко использовать его без дополнительной настройки. Однако из-за его удобства это означает, что многие детали скрыты, поэтому разработчики, которые непосредственно изучают Spring Boot, могут использовать его только без знания внутреннего процесса реализации. Недавно у меня было время, я снова просмотрел соответствующий контент Spring, разобрался с некоторыми вариантами использования сборки Bean и описал изменения и прогресс сборки Bean от разработки Spring в прошлом до текущей разработки Spring.
От интеграции SSM до сборки Bean
В первые дни обучения, я думаю, все зайдут в некоторые блоги, такие как «Spring Spring MVC Mybatis Integration». Шаг за шагом, чтобы интегрировать проект ssm. В то время у меня не было никакой концепции, просто следуйте инструкциям, создайте новый файл конфигурации, вставьте содержимое, а затем запустите, и получился базовый проект скаффолдинга. Подводя итог, в основном это следующие шаги:
- Создайте веб-проект maven и добавьте зависимости в pom.xml.
- Настройте web.xml и добавьте файлы конфигурации spring-*.xml.
- Настройте несколько файлов spring-*.xml, таких как автоматическое сканирование пакетов, статическое сопоставление ресурсов, преобразователь представления по умолчанию, пул соединений с базой данных и т. д.
- Написать код бизнес-логики (дао, сервисы, контроллер)
Позже вам может понадобиться загрузить файлы, а затем перейти в xml для настройки связанных узлов. В разработке в основном следуют шаблону — трехуровневая архитектура, интерфейсно-ориентированное программирование. Если класс является контроллером, добавьте @Controller; если это сервис, добавьте аннотацию @Services, и тогда вы сможете успешно писать бизнес-логику.
Что такое весна? Понимание того времени, настроить его так, плюс несколько аннотаций, это Spring. Другими словами, это то, что делает Spring.
С углублением обучения будет более глубокое понимание Spring.Весной все бобы. Можно сказать, что Bean — это базовая единица приложения Spring. Основная часть Spring (здесь узкое понятие, относящееся к Spring Core) — это управление bean-компонентами.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:annotation-config/>
<context:component-scan base-package="com.zjut.ssm.controller">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<bean id="defaultViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="20971500"/>
<property name="defaultEncoding" value="UTF-8"/>
<property name="resolveLazily" value="true"/>
</bean>
</beans>
Давайте еще раз взглянем на файл конфигурации Spring MVC, в дополнение к некоторым параметрам есть два компонента-узла, внедряющие InternalResourceViewResolver для обработки представлений и внедряющие CommonsMultipartResolver для обработки загрузки файлов. В настоящее время, если вам нужно интегрировать Mybatis для совместной работы, аналогичным образом вы можете внедрить связанные компоненты. Основным компонентом Mybatis является SqlSessionFactory, который управляет базой данных, создавая сеанс. Когда Spring не используется, его можно создать, загрузив XML и прочитав информацию из базы данных.
String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
Очевидно, приведенный выше код не соответствует идее Spring. Чтобы добиться слабой связанности и высокой связности, старайтесь не создавать экземпляр напрямую, а внедрять bean-компоненты через DI, который управляется контейнером Spring IoC. Mybatis официально предоставил пакет MyBatis-Spring. Просто добавьте следующие bean-компоненты для организации работы Mybatis (создайте sqlSessionFactory, откройте Session и т. д.) Содержимое Mybatis не будет здесь расширяться.
<beans>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="typeAliasesPackage" value=""/>
<property name="mapperLocations" value="classpath:mapper/*.xml"/>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<property name="basePackage" value=""/>
</bean>
</beans>
Что ж, теперь мы знаем, что суть настройки Spring через XML и интеграции различных фреймворков заключается в сборке Bean. **Каждый фреймворк состоит из нескольких bean-компонентов N. Если вам нужно его использовать, вы должны собрать соответствующие bean-компоненты в соответствии с требованиями фреймворка. Собранные bean-компоненты управляются контейнером Spring IoC унифицированным образом и могут нормально работать.
Сборка бобов
Существует много способов сборки конкретных bean-компонентов: от XML до Java Config в прошлом и до автоматической настройки Spring Boot — этот процесс постоянно упрощается и становится понятным.
Сборка компонента обычно делится на три этапа: регистрация, сканирование и внедрение.
От XML к конфигурации Java
Компоненты конфигурации XML давно исчезли, и в настоящее времяБолее распространено использование Java Config и аннотаций для сборки Bean.. Конечно, иногда его тоже можно увидеть, например, spring-*.xml для интеграции фреймворка ssm.
Преимущества Java Config заключаются в следующем:
- Java является типобезопасным, и если в процессе сборки возникает проблема, компилятор сообщит об этом напрямую.
- Файл конфигурации XML будет становиться все больше и больше по мере увеличения конфигурации, и его нелегко поддерживать и управлять.
- Java Config легче рефакторить и искать bean-компоненты.
Поэтому далее в основном речь пойдет о способе настройки на основе Java. Основной процесс выглядит следующим образом:
// 注册
@Configuration
public class BeanConfiguration {
@Bean
public AtomicInteger count() {
return new AtomicInteger();
}
}
//或者
@Componment
public class Foo{}
// 扫描
@ComponentScan(basePackages={})
@Configuration
public class BeanConfiguration {}
// 注入
@Autowired
private AtomicInteger c;
Подробно разверните ниже.
Зарегистрированные компоненты Java Config в основном делятся на две категории: зарегистрированные не исходные компоненты и зарегистрированные исходные компоненты.
Регистрация bean-компонентов без исходных кодов
Bean-компоненты без исходного кода относятся к коду, который мы не можем редактировать, в основном вводя внешние фреймворки или зависимости или используя некоторые bean-компоненты Spring. Конфигурация этих bean-компонентов обычно объявляется в виде файлов Java.
создать новый с помощью@Configuration
украшенный класс конфигурации, а затем используйте@Bean
Метод изменения необходимости создания bean-компонента может указывать значение и значение имени (они эквивалентны). Пример выглядит следующим образом:
@Configuration
public class BeanConfiguration {
@Scope("prototype")
@Bean(value = "uploadThreadPool")
public ExecutorService downloadThreadPool() {
return Executors.newFixedThreadPool(10);
}
}
Среди них следует отметить, что:
- Бины создаются в виде синглетонов по умолчанию, и во всем приложении создается только один экземпляр. При необходимости для каждой инъекции создается новый экземпляр, который можно аннотировать.
@Scope("prototype")
. В этом примере пул потоков, созданный по умолчанию, является одноэлементным, и он используется после внедрения в любом месте приложения, и используется тот же пул потоков (глобально совместно используемый); плюс@Scope("prototype")
После этого внедряйте в каждый контроллер отдельно, что означает, что у каждого контроллера есть свой пул потоков, и каждый запрос будет отправлен в свой собственный пул потоков. - При внедрении нескольких bean-компонентов одного типа вручную укажите имя или значение, чтобы различать их. или по
@Primary
, отмечая предпочтительный компонент.
Зарегистрируйте Bean исходного кода
Бин исходного кода относится к написанному нами коду, который обычно не собирается в форме @Bean, а использует другую серию семантических аннотаций. (@Component, @Controller, @Service, @Repository) После добавления этих аннотаций класс становится классом компонентов, управляемым Spring Последние три перечисленные аннотации, скорее всего, будут использоваться, и они в основном стали шаблонными аннотациями. class Add @Controller, а слой Service реализует добавление @Service.
Ниже показан пример объявления вашего собственного инкапсулированного класса через Spring.
@Scope("prototype")
@Component(value = "uploadThread")
public class UploadTask implements Runnable {
private List<ByteArrayInputStream> files;
private List<String> fileNameList;
private PropertiesConfig prop = SpringUtil.getBean(PropertiesConfig.class);
// 如果直接传入MutiPartFile,文件会无法存入,因为对象传递后spring会将tmp文件缓存清楚
public UploadThread(List<ByteArrayInputStream> files, List<String> fileNameList) {
this.files = files;
this.fileNameList = fileNameList;
}
@Override
public void run() {
for (int i = 0; i < files.size(); ++i) {
String fileName = fileNameList.get(i);
String filePath = FileUtils.generatePath(prop.getImageSavePath(),fileName);
FileUtils.save(new File(filePath), files.get(i));
}
}
}
Продолжая пул потоков выше, здесь мы реализуем задачу для обработки задач асинхронной загрузки. В традиционном JUC мы обычно пишем такой код:
private ExecutorService uploadThreadPool = Executors.newFixedThreadPool(10);
uploadThreadPool.submit(new UploadTask(fileCopyList, fileNameList));
Я думаю, что в Spring код должен быть написан более похожим на Spring, поэтому добавьте @Component, чтобы сделать его Spring Bean, а поток не одноэлементным, добавьте аннотацию @Scope. Рефакторинговый код выглядит следующим образом:
@Resource(name = "uploadThreadPool")
private ExecutorService uploadThreadPool;
@PostMapping("/upload")
public RestResult upload(HttpServletRequest request) {
uploadThreadPool.submit((Runnable) SpringUtils.getBean("uploadThread", fileCopyList, fileNameList));
}
Bean-инъекция будет подробно обсуждаться в следующем разделе. На самом деле причин для этого ноль и одна,Компоненты, которые не управляются Spring, как правило, не могут быть напрямую внедрены в Spring Beans.. Если нам нужно реализовать некоторую бизнес-логику в UploadTask, нам может понадобиться внедрить некоторые службы.Лучший способ — сказать, что сам UploadTask также зарегистрирован как Spring Bean, тогда мы можем использовать @Autowired для автоматического внедрения в класс.
Дополнительное внимание: **Из-за некоторых соображений безопасности потоков классы потоков не могут напрямую использовать @Autowired для внедрения bean-компонентов. ** Обычно используетсяSpringUtils.getBean()
Инъекция вручную.
автоматическое сканирование
добавить класс конфигурации@ComponentScan
аннотация. По умолчанию эта аннотация сканирует все классы конфигурации в пакете, в котором находится класс, и можно настроить специальные пакеты.basePackages
Атрибуты. Spring сканирует все bean-компоненты и может использоваться после инъекции.
Инъекция фасоли
Для некоторых bean-компонентов, которые не используются напрямую, после регистрации в контейнере Spring IoC нам не нужно внедрять их вручную. Например, упомянутые ранее три боба Mybatis. Нам нужно только использовать его в соответствии с документом, создать интерфейс Mapper и использовать @Mapper для его изменения.При вызове определенного метода запроса Mybatis будет вводить Beans внутрь и открывать сеанс для работы с базой данных.
Для bean-компонентов, которые нам нужно использовать, нам нужно внедрить их в переменные для использования. Есть два распространенных способа инъекции фасоли.
- Внедрение аннотаций (@Autowired и @Resource).
@Autowired
является наиболее часто используемой аннотацией для внедрения bean-компонентов, по умолчанию используется черезbyTypeспособом вводят. То есть, если он содержит несколько bean-компонентов одного типа, его нельзя внедрить напрямую через @Autowired. В это время внедренный компонент должен быть квалифицирован @Qualifier. Или используйте @Resource.@Resource
Он вводится методом byName, а имя бина может быть указано прямо в аннотации.
public class Foo{
// 正常字段注入
@Autowired
private AtomicInteger c;
// 正常构造器注入
private final AtomicInteger c;
@Autowired
public Foo(AtomicInteger c){this.c = c;}
// 歧义加上@Qualifier
@Autowired
@Qualifier("count")
private AtomicInteger c;
// 歧义直接使用@Resource(与前一种等同)
@Resource("count")
private AtomicInteger c;
}
- Вызовите метод getBean контекста приложения.
Рекомендуется использовать внедрение аннотаций, но в особом случае по умолчанию вам необходимо использовать метод getBean() для внедрения bean-компонентов. Например, упомянутая ранее многопоточная среда. Конкретную реализацию можно увидеть в приложении, которое реализует ApplicationContextAware и может быть инкапсулировано в класс инструмента.
Интегрированная версия SSM для Java
Из-за преимуществ Java Config многие работы по интеграции фреймворка предпочитают не использовать XML-конфигурацию. Например, ViewResolver Spring MVC ранее был настроен в xml и может быть внедрен в Java следующим образом:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Bean
public ViewResolver viewResolver(){
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/view/");
resolver.setSuffix(".jsp");
return resolver;
}
}
Если вам интересно, вы можете использовать Java Config, чтобы интегрировать его самостоятельно.На самом деле, вещи, которые нужно настроить, одинаковы, но в Java для некоторых нужно зарегистрировать соответствующий Bean, а для некоторых нужно реализовать соответствующий интерфейс. С XML на Java, это всего лишь смена языка конфигурации, которая действительно раскрепощает программистов и повышает производительность — это Spring Boot. Основываясь на идее соглашения, а не конфигурации, автоматическая конфигурация значительно сокращает работу по настройке некоторых bean-компонентов по умолчанию.
Spring Boot Magic
Auto Configuration
Далее давайте посмотрим, что необходимо настроить для интеграции SSM на основе Spring Boot.
spring:
datasource:
url: jdbc:mysql://localhost:3306/test
username: root
password: fur@6289
mybatis:
type-aliases-package: com.fur.mybatis_web.mapper
mapper-locations: classpath:mapping/*.xml
Любой, кто использовал Spring Boot, знает, что вышеприведенный файл конфигурации Spring Bootapplication.yml
. Просто добавьте соответствующие зависимости в pom.xml и настройте необходимую информацию в yml. (Независимо от того, насколько умен фреймворк, невозможно узнать информацию о нашей базе данных :smile:) CommonsMultipartResolver, SqlSessionFactoryBean и т. д., которые мы видели раньше, больше не нужно собирать вручную.
Разница между Spring Boot и традиционным SSM заключается в следующем:
- Добавленные зависимости maven отличаются друг от друга
mybatis
иmybatis-spring
сталmybatis-spring-boot-starter
- Больше @SpringBootApplication, меньше @ComponentScan
Spring Boot Starter здесь не представлен, просто знайте, что это новая зависимость, включая автоматическую настройку и другие необходимые зависимости. В зависимостях, представленных в Spring в прошлом, если Boot реализует соответствующий стартер, стартер следует использовать первым.
Давайте посмотрим на исходный код, чтобы увидеть, как Spring Boot реализует автоматическую настройку. Успокойтесь, мы не будем разбирать исходный код построчно, а просто разберем общий процесс.
По пути первое, что вы видите, — это содержимое аннотации @SpringBootApplication, которая, очевидно, является составной аннотацией, в основном включающей @SpringBootConfiguration, @EnableAutoConfiguration и @ComponentScan.
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {}
- @SpringBootConfiguration, который внутренне является @Configuration, как и прежде, аннотированный класс является классом конфигурации Spring.
- @ComponentScan, не чужой. Интегрированный в аннотацию @SpringBootApplication, он добавляется по умолчанию при создании проекта, и нам не нужно вручную включать сканирование bean-компонентов.
- @EnableAutoConfiguration, это ключ к автоматической настройке. Короче говоря, с помощью этой аннотации Spring будет автоматически сканировать импортированные зависимости (jar-пакеты в пути к классам) на наличие проектов, требующих автоматической настройки, и выполнять автоматическую настройку в соответствии с yml.
Посмотрите @enableautoconfiguration и найдите внутренний импортAutoConfigurationImportSelector
Класс, этот класс в основном является основным классом, который обрабатывает работу по автоматической настройке.
// AutoConfigurationImportSelector.java
/**
* Return the auto-configuration class names that should be considered. By default
* this method will load candidates using {@link SpringFactoriesLoader} with
* {@link #getSpringFactoriesLoaderFactoryClass()}.
* @param metadata the source metadata
* @param attributes the {@link #getAttributes(AnnotationMetadata) annotation
* attributes}
* @return a list of candidate configurations
*/
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
getBeanClassLoader());
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
+ "are using a custom packaging, make sure that file is correct.");
return configurations;
}
См. этот метод выше,getCandidateConfigurations()
Функция состоит в том, чтобы получить информацию о зависимости, которая должна быть автоматически настроена.Основная функция предоставляется Spring FactoriesLoaderloadFactoryNames()
метод для завершения.
// SpringFactoriesLoader.java
public final class SpringFactoriesLoader {
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
/**
* Load the fully qualified class names of factory implementations of the
* given type from {@value #FACTORIES_RESOURCE_LOCATION}, using the given
* class loader.
* @param factoryClass the interface or abstract class representing the factory
* @param classLoader the ClassLoader to use for loading resources; can be
* {@code null} to use the default
* @throws IllegalArgumentException if an error occurs while loading factory names
* @see #loadFactories
*/
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
}
Вот краткое описание процесса, если интересно, можете посмотреть исходный код этого класса. SpringFactoriesLoader просканирует все пакеты jar в пути к классам и загрузит содержимое в META-INF/spring.factories. В качестве примера возьмем mybatis-spring-boot-starter.Существует зависимость от mybatis-spring-boot-autoconfigure.Вы можете видеть, что существует META-INF/spring.factories.
Содержание следующее:
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
Далее ключ будет получен какorg.springframework.boot.autoconfigure.EnableAutoConfiguration
значение . То есть конкретный класс автоматической настройки Mybatis. можно увидеть в упаковкеorg.mybatis.spring.boot.autoconfigure
вниз, естьMybatisAutoConfiguration
иMybatisProperties
, первый — это класс автоматической настройки, второй — некоторые параметры, используемые для настройки, соответствующие паре ключ-значение в узле mybatis в yml. Вставьте исходный код ниже:
// MybatisAutoConfiguration.java
@org.springframework.context.annotation.Configuration
@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })
@ConditionalOnSingleCandidate(DataSource.class)
@EnableConfigurationProperties(MybatisProperties.class)
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
public class MybatisAutoConfiguration implements InitializingBean {
@Bean
@ConditionalOnMissingBean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
factory.setDataSource(dataSource);
// 省略
return factory.getObject();
}
}
Здесь мы видим знакомую нам SqlSessionFactory, которую раньше нужно было вводить вручную, теперь через@ConditionalOnMissingBean
, когда bean-компонент не существует в контейнере Spring, он будет автоматически подключен для нас.
Следующая блок-схема является кратким описанием всего процесса автоматической настройки.
Syntactic sugar
На самом деле это составная аннотация.В дополнение к автоматической сборке, где соглашение больше, чем конфигурация, Spring Boot также оборачивает @ComponentScan и @SpringBootConfiguration через большую составную аннотацию @SpringBootApplication, так что класс запуска можно использовать напрямую. в качестве класса конфигурации и сокращает сканирование Bean на этом шаге.
Суммировать
Эта статья не является полным учебным пособием по Spring IoC, а просто разбирает использование и изменения в сборке Bean на пути от Spring к Spring Boot. Видно, что это процесс постоянного упрощения и постоянного улучшения, но ядро остается прежним, поэтому даже если вы обратитесь к Spring Boot для разработки, вам все равно нужно использовать технические моменты, связанные со Spring IoC, при столкновении с каким-то сложным бизнесом. . , такие как управление областью действия bean-компонентов, условных bean-компонентов и т. д.
использованная литература
- Глава 5 Принцип автоматической настройки Spring Boot
- Почему Spring Boot так популярен?
- «Весна в действии».
приложение
SpringUtils.java
@Component
public class SpringUtils implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if (SpringUtil.applicationContext == null) {
SpringUtil.applicationContext = applicationContext;
}
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
public static Object getBean(String name) {
return getApplicationContext().getBean(name);
}
public static <T> T getBean(Class<T> clazz) {
return getApplicationContext().getBean(clazz);
}
public static <T> T getBean(String name, Class<T> clazz) {
return getApplicationContext().getBean(name, clazz);
}
public static <T> T getBean(String name, Object... args) {
return (T) getApplicationContext().getBean(name, args);
}
}
Способ получения Spring Bean в не-Spring Bean
Чтобы получить Spring Beans в не-Spring Bean, вам нужно преобразовать SpringUtils.java, удалить @Component и не нужно реализовывать интерфейсы, а также вручную внедрить Spring Context.
public class SpringUtils {
private static ApplicationContext applicationContext;
public static void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if (SpringUtil.applicationContext == null) {
SpringUtil.applicationContext = applicationContext;
}
}
// 余下代码如上
}
public class SkeletonApplication {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(SkeletonApplication.class, args);
SpringUtils.setApplicationContext(context);
}
}