Spring实战 | 番外篇: 搭建Spring环境实现helloworld、Bean配置、Spring容器

2年前 (2022) 程序员胖胖胖虎阿
142 0 0

一、IntelliJ IDEA搭建Spring环境,实现helloworld

二、spring简介

三、配置形式

四、bean的配置方式

五、IOC和DI

六、在Spring的IOC容器里配置bean

七、关于ApplicationContext的介绍

八、依赖注入的方式

九、Spring容器

一、IntelliJ IDEA搭建Spring环境,实现helloworld

1、创建project

20170424151734669.jpg

2、勾选Spring然后next

20170424152027142.jpg

3、设置你项目所想要存放的路径以及名字

20170424152112674.jpg

4、这时候IntelliJ IDEA就会自动下载Spring所需要的jars,只需要等待就好。

20170424152415189.jpg

5、下载好后,Spring的jars和配置文件都准备好了。

20170424152513274.jpg

6、Spring实现hello world

普通的方法:

20170424155252327.jpg

20170424155549831.jpg

接着我们运行一下这个程序,成功输出了Hello Spring。

è¿éåå¾çæè¿°

接下来我们就要使用Spring了,首先在Spring的配置文件中加入如下内容。

<?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="helloWorld" class="HelloWorld">
    <property name="name" value="Spring"></property>
</bean>
</beans>

这时候我们就配置好了HelloWorld Bean的信息,我们再调用sayHello()方法的时候就不向之前一样了,也需要3个步骤。

  1. 创建一个Spring的IOC容器对象
  2. 从IOC容器中获取Bean实例
  3. 调用sayHello()方法
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class HelloWorld {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void sayHello(){
        System.out.println("hello "+name);
    }

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        HelloWorld helloWorld = (HelloWorld) context.getBean("helloWorld");
        helloWorld.sayHello();
    }
}

这么写好像和自己之前编程的时候不一样啊,可以运行结果吗,我们直接试一下就好。

fbce8d6a1a43144f9a81703f65d9b29147a.jpg

好像不太一样啊,输出了我们想要的Hello Spring ,但是好像多了许多其他的东西啊。这些其实是Spring输出的日志而已。
第一次使用Spring,我们明明没有创建HelloWorld的实例对象,只是配置了下Spring的配置文件,怎么就能得出正确的结果呢,这是因为我们使用了Spring的IOC功能,把对象的创建和管理的功能都交给了Spring去管理,我们需要对象的时候再和Spring去要就行。

那么什么时候new的对象呢?

我也不知道,哈哈,所以首先修改一下HelloWorld类的构造方法和setter方法。

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

public class HelloWorld {
    private String name;

    public HelloWorld() {
        System.out.println("this is helloworld constructor");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        System.out.println("this is helloworld setName()");
        this.name = name;
    }

    public void sayHello(){
        System.out.println("hello "+name);
    }

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        HelloWorld helloWorld = (HelloWorld) context.getBean("helloWorld");
        helloWorld.sayHello();
    }
}

然后直接添加断点进入Debug模式。

b0144f6a6d9b374c993e265c04e9445e01b.jpg

我们可以看到,当执行到第一步创建IOC容器对象的时候就调用了HelloWorld类的构造方法和setter方法。

从上面的例子可以看出:

旧方法:

1、创建helloworld实例

2、设置实例对象的name属性

3、调用sayhello方法

spring:

1、创建spring的IOC容器

2、从IOC容器中获取Bean对象

3、调用sayhello方法

然后我们研究了spring是啥时候new对象的,可以看出,spring帮我们完成了前两步,也就是创建实例对象和设置对象属性,也就是说我们可以把对象的创建和管理工作交给spring去完成,只要写好spring的配置文件即可。

二、spring简介

1、spring是一个开源框架

2、spring是为了简化企业级应用开发而生

3、javabean实现EJB的功能

4、spring是Java一站式框架

spring优点

1、方便解耦,简单开发

2、支持AOP编程

3、支持声明事务

4、方便程序测试

5、方便框架集合

6、降低开发难度

三、配置形式

1、基于xml文件的方式

2、基于注解的方式

四、bean的配置方式

1、通过全类名(反射)

2、通过工厂方法(静态工厂方法&实例工厂方法)

3、FactoryBean

五、IOC和DI

IOC(inversion of control):其思想是反转资源获取的方式。传统的资源查找方式要求组件向容器发起请求查找资源,作为回应,容器适时的返回资源。而应用了IOC之后,容器主动将资源推送给它所管理的组件,组件要做的仅是选择一种合适的方式接收资源。这种行为也被称为查找的被动形式。

DI(Dependency Injection):IOC的另一种表达方式:即组件以一些预先定义好的方式(例如:setter方法)接收来自如容器的资源注入。相对于IOC而言,这种表述更为直接。

六、在Spring的IOC容器里配置bean

只有springIOC容器本身实例化后,才能从IOC容器里获取bean实例并使用。

spring提供了两种类型的IOC容器实现:

1、beanFactory:是spring框架的基础设施,面向spring本身

2、ApplicationContext:面向使用spring框架的开发者,几乎所有的应用场合都直接使用ApplicationContext而非底层的beanFactory,提供了更多的高级特性,ApplicationContext是beanFactory的子接口。

七、关于ApplicationContext的介绍

30067df3a91af89418e4e6d8ced9c51ea7d.jpg

ApplicationContext的主要实现类:

1、ClassPathXmlApplicationContext:从类路径下加载配置文件

2、FileSystemXmlApplicationContext:从文件系统中加载配置文件

子接口ConfigurableApplicationContext 的作用:扩展于ApplicationContext,新增加两个主要方法:refresh()和close(),让ApplicationContext具有启动、刷新和关闭上下文的能力。

ApplicationContext在初始化上下文时就实例化所有单例的bean。

WebApplicationContext是专门为web应用而准备的,它允许从相对于web根目录的路径汇总完成初始化工作。

八、依赖注入的方式

spring支持3种依赖注入的方式

1、属性注入

属性注入即通过setter方法注入bean的属性值或依赖的对象

属性注入使用元素,使用name属性指定bean的属性名称,value属性或子节点属性值

属性注入是实际开发中最常见的注入方式

public void setName(String name)
{
    System.out.println("setName:"+name);
    this.name=name;
}
<bean id="helloWorld" class="spring.bean.HelloWorld">
    <property name="name" value="Spring"></property>
</bean>

2、构造器注入

通过构造方法注入bean的属性值或者依赖的对象(引用),保证了bean实例在实例化后就可以使用

构造器注入在元素里声明属性,没有name属性

创建一个People对象

package com.container;

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

public class People {
        private String name;
        private String sex;
        private int age;

        public People(String name, int age) {
            this.name = name;
            this.age = age;
        }

        public People(String name, String sex) {
            this.name = name;
            this.sex = sex;
        }

        @Override
        public String toString() {
            return "people{" +
                    "name='" + name + '\'' +
                    ", sex='" + sex + '\'' +
                    ", age=" + age +
                    '}';
        }

        public static void main(String[] args) {
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-config.xml");
            People people1 = (com.container.People) applicationContext.getBean("people1");
            System.out.println(people1);
            People people2 = (com.container.People) applicationContext.getBean("people2");
            System.out.println(people2);
        }
    }
<?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="people1" class="com.container.People">
        <constructor-arg value="江疏影" type="java.lang.String"></constructor-arg>
        <constructor-arg value="20" type="int"></constructor-arg>
    </bean>
    <bean id="people2" class="com.container.People">
        <constructor-arg value="江疏影" type="java.lang.String"></constructor-arg>
        <constructor-arg value="man" type="java.lang.String"></constructor-arg>
    </bean>
</beans>

d3c3fdcaafa108a65f7c71dac6138f1012e.jpg

3、工厂方法注入(知道就行,不推荐)

九、spring容器

Spring容器,顾名思义是用来容纳东西的,装的就是Bean。Spring容器负责创建、配置、管理Bean。spring容器有两个核心接口:BeanFactory和ApplicationContext接口,后者是前者的子接口。在基于spring的Java EE程序中,所有的组件都被当成Bean来处理,包括数据源对象、hibernate的sessionFactory、事务管理等,程序中的所有Java类都可以被当成spring容器中的bean。

 1、spring容器

spring容器的核心接口是BeanFactory,它有一个子接口就是ApplicationContext。ApplicationContext也被称为spring上下文。

调用者只需要使用getBean()方法即可获得指定bean的引用。对于大部分的Java程序而言,使用ApplicationContext作为spring容易更为方便。其常用的实现类有FileSystemXmlApplicationContext、ClassPathXmlApplicationContext和AnnotationConfigXmlApplicationContext。如果Java web中使用spring容器,则通常有XmlWebApplicationContext、AnnotationConfigWebApplicationContext两个容器。

创建spring容器的实例时,必须提供spring容器管理的bean的配置文件,也就是我们常说的spring.xml配置文件。因此在创建beanFactory时配置文件作为参数传入。xml配置文件一般以resource对象传入。resource是spring提供的资源访问接口,通过该接口spring更简单、透明的访问磁盘,网络系统和类路径上的相关资源。

对于独立的Java EE应用程序,可以通过如下方法来实例化BeanFactory。

//在当前项目类路径下搜索配置文件
ApplicationContext appContext = new ClassPathXmlApplicationContext("beans_7_3_3.xml");
//在文件系统搜索配置文件
appContext = new FileSystemXmlApplicationContext("D:\\spring-tool-workspace\\myspring\\src\\beans_7_3_3.xml");
//获取chinese的Bean,并且返回的类型为Chinese
Person chinese = appContext.getBean("chinese", Chinese.class);
chinese.useAxe();

2、使用ApplicationContext

大部分时间,都不会使用beanFactory实例作为spring容器,而是使用ApplicationContext作为spring容器,因此spring容器也被称为spring上下文。ApplicationContext增强了beanFactory的功能,提供了很多有用、方便开发的功能。

在web中可以利用如contextLoader的支持类,在web应用启动的时候自动创建ApplicationContext。

除了提供beanFactory所支持的全部功能外,application还额外的提供如下功能:

① ApplicationContext会默认初始化所有的singleton bean(单例bean),也可以通过配置取消。

② ApplicationContext继承了messageSource接口,因此提供国际化支持。

③ 资源访问,比如URL和文件。

④ 事件机制。

⑤ 同时加载多个配置文件。

⑥ 以声明式方式启动并创建spring容器。

ApplicationContext包括beanFactory的所有功能,并提供了一些额外的功能,优先使用ApplicationContext。对于在内存消耗的才使用beanFactory。

当系统创建ApplicationContext容器时,会默认初始化singleton bean,包括调用构造器创建该bean的实例,通过元素驱动spring调用setting方法注入所依赖的对象。这就意味着,系统前期创建ApplicationContext会有很大的开销,但是一旦初始化完成后面获取bean实例就会拥有较好的性能。为了阻止在使用ApplicationContext作为spring容器初始化singleton bean可以在元素添加lazy-init="true"属性。

3、ApplicationContext的国际化支持

ApplicationContext接口继承了MessageSource接口,因此具备国际化功能。

//MessageSource接口提供的国际化的两个方法
String getMessage(String code, Object [] args, Locale loc){
}
String getMessage(String code, Object[]args, String default, Locale loc){
}

spring国际化的支持,其实是建立在Java国际化的基础上的。其核心思路将程序中需要国际化的消息写入资源文件,而代码中仅仅使用国际化信息响应的key。

4、ApplicationContext的事件机制

ApplicationContext的事件机制是观察者设计模式的实现。通过ApplicationEvent和ApplicationListener接口实现,前者是被观察者,后者是观察者。

spring事件框架有两个核心的接口:

ApplicationEvent(事件):必须由ApplicationContext来发布。

ApplicationListener(监听器):实现了此接口就可以担任容器中的监听器bean。

实际上,spring的事件机制是由事件(实现ApplicationEvent接口的类)、事件源(也就是spring容器,并且有Java代码显示的触发)、监听器(ApplicationListener接口实现类)。这就像我们在页面点击一个button。button是事件源,单机的这个动作就是事件,处理函数就是监听器。

以下代码演示spring事件机制:

import org.springframework.context.ApplicationEvent;

public class EmailEvent extends ApplicationEvent{
    private String address;
    private String text;
    public EmailEvent(Object source) {
        super(source);
    }

    public EmailEvent(Object source, String address, String text) {
        super(source);
        this.address = address;
        this.text = text;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }
}
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class EmailNotifier implements ApplicationListener {
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        //处理email事件
        if(event instanceof EmailEvent){
            EmailEvent email = (EmailEvent) event;
            System.out.println(email.getAddress()+"  "+email.getText());
        }else {
            //输出spring容器的内置事件
            System.out.println("其它事件:"+event);
        }
    }

    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans_7_4_4.xml");
        EmailEvent emailEvent = applicationContext.getBean("emailEvent",EmailEvent.class);
        applicationContext.publishEvent(emailEvent);
    }
}
<?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 class="EmailNotifier"></bean>
    <bean id="emailEvent" class="EmailEvent">
        <constructor-arg value="test"></constructor-arg>
        <constructor-arg value="123@qq.com"></constructor-arg>
        <constructor-arg value="this is a test"></constructor-arg>
    </bean>
</beans>

32d15c15c46f5eb3ba181f40c4fda7a8b82.jpg

从上面的代码可以看出,事件监听器不仅监听到了我们程序显示触发的事件,还监听了spring容器内置的事件。如果实际开发需要,我们可以在spring容器初始化或销毁时回调自定义方法,就可以通过上面的事件监听机制来完成。

spring提供了如下几个内置对象:

ContextRefreshedEvent、ContextStartedEvent、ContextClosedEvent、ContextStoppedEvent、RequestHandledEvent。

5、让bean获取spring容器

上面都是通过ApplicationContext创建spring容器,再调用spring容器的getBean()方法获取bean。这种情况下,程序总是持有spring容器的引用。但是在web应用中,我们可以用声明式的方法来创建spring容器:在web.xml文件中配置一个监听,让这个监听类帮我们来创建spring容器,前端MVC框架直接调用bean,使用依赖注入功能,无需访问spring容器本身。

在某些特殊情况下,bean需要实现某个功能(比如:bean需要输出国际化信息,或向spring容器发布事件),这些功能都需要借助spring容器来完成。就是说我们需要将spring容器作为一个bean来注入到其它bean中,只不过spring容器bean是一个容器级别的bean。

为了让bean获取它所在容器的引用,可以让bean实现beanFactoryAware接口。该接口只有一个方法setBeanFactory(BeanFactory beanFactory)方法,方法的beanFactory参数指向spring容器,会由spring容器注入。我们bean中定义一个setter方法后,通常都是由在配置文件中配置元素来驱动spring容器来注入依赖bean的,但是这里我们并没有这样做,这是因为一个bean如果实现了beanFactory接口,spring在创建该bean时,会自动注入spring容器本身。与beanFactoryAware接口类似的还有BeanNameAware、ResourceLoaderAware接口,这些接口都会提供类似的setter方法,这些方法会由spring容器来注入。

 

Spring实战@目录

相关文章

暂无评论

暂无评论...