Spring源码初识一 Spring项目搭建与使用

本文详述了Spring框架的搭建过程,包括Xml、JavaConfig及两者组合的方式,并介绍了Bean的相关操作如实例化、依赖注入、生命周期管理。此外,讨论了注解的使用,如@Autowired、@Primary、@Qualifier等,并涵盖了事件监听机制。
摘要由CSDN通过智能技术生成

官网地址https://github.com/spring-projects/spring-framework
中文文档https://github.com/DocsHome/spring-docs/blob/master/SUMMARY.md
家族清单https://spring.io/projects

本文内容主要摘自中文文档中内容,详细内容可参考中文文档

一、搭建Spring项目

1、第一个spring项目(Xml方式)

1.1、引入pom文件

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.5.RELEASE</version>
</dependency>

1.2、添加bean对应类

public class TestService {
    public void sayHello() {
        System.out.println("你好");
    }
}

1.3、在resources下添加services.xml

<?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.xsd">
    <bean id="testService" class="service.TestService">
    </bean>
</beans>

1.4、写main方法

public static void main(String[] args) {
    ApplicationContext context = new ClassPathXmlApplicationContext("services.xml");
    TestService bean = context.getBean(TestService.class);
    bean.sayHello();
}

1.5、查看运行效果

你好
Process finished with exit code 0

2、第一个spring项目(JavaConfig方式)

2.1、引入pom文件

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.5.RELEASE</version>
</dependency>

2.2、添加bean对应类

public class ConfigTestService {
    public void sayHello() {
        System.out.println("config:你好");
    }
}

2.3、添加config对应类

@Configuration
public class MyConfig {
    @Bean
    public ConfigTestService configTestService() {
        return new ConfigTestService();
    }
}

2.4、写main方法

public static void main(String[] args) {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
    ConfigTestService bean = context.getBean(ConfigTestService.class);
    bean.sayHello();
}

2.5、查看运行效果

config:你好
Process finished with exit code 0

3、第一个spring项目(JavaConfig+xml组合方式)

3.1、修改main方法

public static void main(String[] args) {
   AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
   new XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml");
   context.register(MyConfig.class);
   context.refresh();
   ConfigTestService bean = context.getBean(ConfigTestService.class);
   bean.sayHello();
   TestService bean2 = context.getBean(TestService.class);
   bean2.sayHello();
}

3.2、查看运行效果

config:你好
你好

Process finished with exit code 0

二、Spring详细功能使用

选择BeanFactory还是ApplicationContext?

FeatureBeanFactoryApplicationContext
Bean Bean实例化/装配YesYes
集成的生命周期管理rNoYes
自动注册 BeanPostProcessorNoYes
自动注册 BeanFactoryPostProcessorNoYes
便利的 MessageSource 访问 (国际化)NoYes
内置ApplicationEvent 发布机制NoYes

1、Bean相关

1.1、为Bean起别名

每个bean都有一个或多个标识符,这些标识符在容器托管时必须是唯一的。bean通常只有一个标识符,但如果需要到的标识不止一个时,可以考虑使用别名
xml方式:

<bean name="aaa,bbb,ccc" />
或者
<alias name="testService" alias="toName"/>

javaConfig方式:

@Bean(name = {"a", "b", "c"})

1.2、实例化Bean

bean定义基本上就是用来创建一个或多个对象的配置,当需要bean的时候,容器会查找配置并且根据bean定义封装的元数据来创建(或获取)实际对象。

1.2.1 无参构造函数

xml方式:

<bean id="exampleBean" class="examples.ExampleBean"/>
<bean name="anotherExample" class="examples.ExampleBeanTwo"/>

或javaConfig:

@Bean
1.2.2、静态工厂创建Bean

xml方式:

<bean id="clientService" class="service.ClientService" factory-method="createInstance"/>
1.2.3、实例工厂创建Bean

xml方式:

<bean id="serviceLocator" class="examples.DefaultServiceLocator"/>
<bean id="clientService"  factory-bean="serviceLocator" factory-method="createClientServiceInstance"/>

1.3、依赖注入

依赖注入主要使用两种方式,一种是基于构造函数的注入,另一种的基于Setter方法的依赖注入。

1.3.1 构造函数注入
<bean id="thingOne" class="x.y.ThingOne">
   <constructor-arg ref="thingTwo"/>
   <constructor-arg type="java.lang.String" value="42"/>
   <constructor-arg index="2" value="7500000"/>
</bean>
1.3.2 setter方法注入
<bean id="exampleBean" class="examples.ExampleBean">
    <!-- setter injection using the nested ref element -->
    <property name="beanOne">
        <ref bean="anotherExampleBean"/>
    </property>

    <!-- setter injection using the neater ref attribute -->
    <property name="beanTwo" ref="yetAnotherBean"/>
    <property name="integerProperty" value="1"/>
</bean>
1.3.3 depends-on属性

依赖另一个bean

<bean id="beanOne" class="ExampleBean" depends-on="manager"/>
1.3.4 懒加载
<bean id="lazy" class="com.something.ExpensiveToCreateBean" lazy-init="true"/>
1.3.5 自动装配
模式说明
no(默认) 不自动装配。Bean引用必须由 ref 元素定义,对于比较大的项目的部署,不建议修改默认的配置 ,因为明确指定协作者可以提供更好的控制和清晰度。在某种程度上,它记录了系统的结构。
byName按属性名称自动装配。 Spring查找与需要自动装配的属性同名的bean。 例如,如果bean配置为根据名字装配,他包含 的属性名字为master(即,它具有setMaster(…)方法),则Spring会查找名为 master 的bean定义并使用它来设置属性。
byType如果需要自动装配的属性的类型在容器中只存在一个的话,他允许自动装配。如果存在多个,则抛出致命异常,这表示您不能对该bean使用byType自动装配。 如果没有匹配的bean,则不会发生任何事情(未设置该属性)。
constructor类似于byType,但应用于构造函数参数。 如果容器中没有一个Bean的类型和构造函数参数类型一致的话,则会引发致命错误。
1.3.6 作用域
作用域描述
singleton(默认) 每一Spring IOC容器都拥有唯一的实例对象。
prototype一个Bean定义可以创建任意多个实例对象.
request将单个bean定义范围限定为单个HTTP请求的生命周期。 也就是说,每个HTTP请求都有自己的bean实例,它是在单个bean定义的后面创建的。 只有基于Web的Spring ApplicationContext的才可用。
session将单个bean定义范围限定为HTTP Session的生命周期。 只有基于Web的Spring ApplicationContext的才可用。
application将单个bean定义范围限定为ServletContext的生命周期。 只有基于Web的Spring ApplicationContext的才可用。
websocket将单个bean定义范围限定为 WebSocket的生命周期。 只有基于Web的Spring ApplicationContext的才可用。
<bean scope="singleton"/>
<bean scope="prototype"/>
...
@RequestScope
@SessionScope
@ApplicationScope
...

1.4、 Bean生命周期

1.4.1 实现InitializingBean 和 DisposableBean 回调接口
1.4.2 自定义 init() 和 destroy() 方法
1.4.3 @PostConstruct 和 @PreDestroy 注解
1.4.4 实现Lifecycle接口:需显示调用ApplicationContext的start方法
1.4.5 实现SmartLifecycle 接口
1.4.6 实现Aware

2、 注解

2.1、@Required

@Required注解适用于bean属性setter方法

public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Required
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    // ...
}

2.2、@Autowired

可以在构造器上使用@Autowired注解:

public class MovieRecommender {

    private final CustomerPreferenceDao customerPreferenceDao;

    @Autowired
    public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
        this.customerPreferenceDao = customerPreferenceDao;
    }

    // ...
}

@Autowired注解应用于“传统”setter方法

public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Autowired
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    // ...
}

还可以将注解应用于具有任意名称和多个参数的方法

public class MovieRecommender {

    private MovieCatalog movieCatalog;

    private CustomerPreferenceDao customerPreferenceDao;

    @Autowired
    public void prepare(MovieCatalog movieCatalog,
            CustomerPreferenceDao customerPreferenceDao) {
        this.movieCatalog = movieCatalog;
        this.customerPreferenceDao = customerPreferenceDao;
    }

    // ...
}

还可以将@Autowired应用于字段,甚至可以和构造函数混合使用

public class MovieRecommender {

    private final CustomerPreferenceDao customerPreferenceDao;

    @Autowired
    private MovieCatalog movieCatalog;

    @Autowired
    public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
        this.customerPreferenceDao = customerPreferenceDao;
    }

    // ...
}

2.3、@Primary

如果存在多个候选者且另一个bean只需要一个特定类型的bean依赖时,使用标记有@Primary注解的Bean就是自动注入的值

@Configuration
public class MovieConfiguration {

    @Bean
    @Primary
    public MovieCatalog firstMovieCatalog() { ... }

    @Bean
    public MovieCatalog secondMovieCatalog() { ... }

    // ...
}

2.4、@Qualifier

筛选指定值的bean

public class MovieRecommender {

    @Autowired
    @Qualifier("main")
    private MovieCatalog movieCatalog;

    // ...
}

2.5、@Resource

根据名字注入

public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Resource
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }
}

2.6、@Component

@Repository, @Service, 或 @Controller是@Component的特殊化

2.7、@ComponentScan

<context:component-scan base-package="org.example"/>
@Configuration
@ComponentScan(basePackages = "org.example")
public class AppConfig  {
    ...
}
@Configuration
@ComponentScan(basePackages = "org.example",
        includeFilters = @Filter(type = FilterType.REGEX, pattern = ".*Stub.*Repository"),
        excludeFilters = @Filter(Repository.class))
public class AppConfig {
    ...
}

2.8、@Scope

2.9、@Inject

同@Autowired

2.10、@Named

@Named 和 @ManagedBean注解: 标准与 @Component 注解相同
@javax.inject.Named 或 javax.annotation.ManagedBean可以使用下面的方式来替代@Component注解:

import javax.inject.Inject;
import javax.inject.Named;

@Named("movieListener")  // @ManagedBean("movieListener") could be used as well
public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Inject
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    // ...
}

2.11、@Description

Bean 的描述

@Configuration
public class AppConfig {

    @Bean
    @Description("Provides a basic example of a bean")
    public Thing thing() {
        return new Thing();
    }
}

2.12、@Import

就像在Spring XML文件中使用元素来帮助模块化配置一样,@Import 注解允许从另一个配置类加载@Bean定义

@Configuration
public class ConfigA {

    @Bean
    public A a() {
        return new A();
    }
}

@Configuration
@Import(ConfigA.class)
public class ConfigB {

    @Bean
    public B b() {
        return new B();
    }
}

2.13、@PropertySource

@Configuration
@PropertySource("classpath:/com/myco/app.properties")
public class AppConfig {

    @Autowired
    Environment env;

    @Bean
    public TestBean testBean() {
        TestBean testBean = new TestBean();
        testBean.setName(env.getProperty("testbean.name"));
        return testBean;
    }
}

Spring的组件模型元素 vs JSR-330 变量

Springjavax.inject.*javax.inject restrictions / comments
@Autowired@Inject@Inject 没有’required’属性。 可以与Java 8的 Optional一起使用。
@Component@Named / @ManagedBeanJSR-330不提供可组合模型,只是一种识别命名组件的方法。
@Scope(“singleton”)@SingletonJSR-330的默认作用域就像Spring的prototype。 但是,为了使其与Spring的一般默认值保持一致,默认情况下,Spring容器中声明的JSR-330 bean是一个 singleton。 为了使用除 singleton之外的范围,您应该使用Spring的@Scope注解。 javax.inject还提供了@Scope注解。 然而,这个仅用于创建自己的注解。
@Qualifier@Qualifier / @Namedjavax.inject.Qualifier 只是用于构建自定义限定符的元注解。 可以通过javax.inject.Named创建与Spring中@Qualifier一样的限定符。
@Value-
@Required-
@Lazy-
ObjectFactoryProviderjavax.inject.Provider avax.inject.Provider是Spring的ObjectFactory的直接替代品, 仅仅使用简短的get()方法即可。 它也可以与Spring的@Autowired结合使用,也可以与非注解的构造函数和setter方法结合使用。

3、事件

Spring提供的标准事件::

事件说明
ContextRefreshedEvent初始化或刷新ApplicationContext时发布(例如,通过使用ConfigurableApplicationContext 接口上的refresh() 方法)。 这里,“initialized”意味着加载所有bean,检测并激活bean的后置处理器,预先实例化单例,并且可以使用ApplicationContext对象。 只要上下文尚未关闭,只要所选的ApplicationContext实际支持这种“热”刷新,就可以多次触发刷新。 例如,XmlWebApplicationContext支持热刷新,但GenericApplicationContext 不支持。
ContextStartedEvent通过使用ConfigurableApplicationContext接口上的start()方法启动ApplicationContext 时发布。 通常,此信号用于在显式停止后重新启动Bean,但它也可用于启动尚未为自动启动配置的组件(例如,在初始化时尚未启动的组件)。
ContextStoppedEvent通过使用ConfigurableApplicationContext接口上的close() 方法停止ApplicationContext时发布。 这里,“已停止”表示所有生命周期bean都会收到明确的停止信号。 可以通过start()调用重新启动已停止的上下文。
ContextClosedEvent通过使用ConfigurableApplicationContext接口上的close()方法关闭ApplicationContext时发布。 这里, “关闭” 意味着所有单例bean都被销毁。 封闭的环境达到其寿命终结。 它无法刷新或重新启动。
RequestHandledEvent一个特定于Web的事件,告诉所有bean已经为HTTP请求提供服务。 请求完成后发布此事件。 此事件仅适用于使用Spring的DispatcherServlet的Web应用程序。

3.1、定义事件

public class BlackListEvent extends ApplicationEvent {

    private final String address;
    private final String content;

    public BlackListEvent(Object source, String address, String content) {
        super(source);
        this.address = address;
        this.content = content;
    }

    // accessor and other methods...
}

3.2、发布事件

public class EmailService implements ApplicationEventPublisherAware {

    private List<String> blackList;
    private ApplicationEventPublisher publisher;

    public void setBlackList(List<String> blackList) {
        this.blackList = blackList;
    }

    public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
        this.publisher = publisher;
    }

    public void sendEmail(String address, String content) {
        if (blackList.contains(address)) {
            publisher.publishEvent(new BlackListEvent(this, address, content));
            return;
        }
        // send email...
    }
}

3.3、监听事件

public class BlackListNotifier implements ApplicationListener<BlackListEvent> {

    private String notificationAddress;

    public void setNotificationAddress(String notificationAddress) {
        this.notificationAddress = notificationAddress;
    }

    public void onApplicationEvent(BlackListEvent event) {
        // notify appropriate parties via notificationAddress...
    }
}

3.4、基于注解的事件监听器

public class BlackListNotifier {

    private String notificationAddress;

    public void setNotificationAddress(String notificationAddress) {
        this.notificationAddress = notificationAddress;
    }

    @EventListener
    public void processBlackListEvent(BlackListEvent event) {
        // notify appropriate parties via notificationAddress...
    }
}
@EventListener({ContextStartedEvent.class, ContextRefreshedEvent.class})
public void handleContextStart() {
    ...
}
@EventListener(condition = "#blEvent.content == 'my-event'")
public void processBlackListEvent(BlackListEvent blEvent) {
    // notify appropriate parties via notificationAddress...
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值