Day47-Spring -01 - 入门-配置详解-实例化和注入 - spring和servlet的整合

一、Spring 核心

IOC(控制反转) + AOP(面向切面编程)

  • IOC:Inversion Of Control 控制反转
    其实把对象的创建工作这个控制权交给spring。

  • AOP:面向切面编程
    其实就是在不改动原来代码的前提下, 对这份功能进行增强、扩展。


二、IOC的演变过程

这里写图片描述


三、Spring 入门案例 及 配置详解

  1. 导入jar包
    我们学习的Spring的版本是4.2.9版本,完全的Spring的jar包共有60个之多,分为三个三个一组,而我们写基本的Spring程序只需要导入核心的四个jar包就可以了
    core | bean | context | expression
    这里写图片描述

  2. 在src下新建xml文件 ,并且导入约束
    约束文件的名字一般情况下写作是applicationContext.xml,当然也可以是别的名字
    找约束文件的模板:在Spring的官方提供的文档里面:Spring\docs\spring-framework-reference\html,拉到最下面的一个文件:xsd-configuration.html,里面有详细的约束。
    也可以手动导入约束模板!!

  3. 使用bean标签指定spring托管具体类
    配置applicationContext.xml,注意这是xsd的约束,写法和dtd的约束写法不尽相同,所有的标签都写在根标签之内

<?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">


        <!-- 告诉spring,让它托管这个类,以便以后,我们只要拿着us 来找他的工厂,就能够创建这个类的实例给我们 -->
        <!-- bean : 代表的是要托管的一个类。 spring把所有被托管的类, 都看成是 bean
                id : 托管的而每一个bean 都给一个标识符, 这个标识符具有唯一性。

                class: 托管的每一个类的全路径地址,因为spring后面要根据这个路径通过反射来创建该类的实例

                scope : 指定创建该类实例是单例还是多例, 默认是单例, singleton . 如果想创建多例, 那么指定prototype,如果是单例的情况下,是在工厂一加载的时候就会创建对象
            -->
        <bean id="us" class="com.xxx.service.impl.UserServiceImpl" scope="prototype"></bean>

</beans>
  1. 在代码里面通过工厂获取实例对象
//1.获得工厂实例
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

//2. 要问工厂要实例,但是我们得告诉工厂要谁的实例。
UserService userService = (UserService) context.getBean("us");

userService.save();

//这行代码以后都不会写了,因为咱们以后写的是web工程, 工厂以后也不是我们创建 工厂会一直跟着项目
((AbstractApplicationContext) context).close();
  1. 由于spring框架里面输出日志需要第三方的日志包,所以还需要导入日志jar包,还有log4j的日志文件
    官方推荐使用slf4j的日志包,更加的高效。

配置详解:

applicationContext.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="userService" class="com.xxx.service.impl.UserServiceImpl" scope="prototype"></bean>
</beans>
<beans> 根标签:
     根标签已经固定,xsd约束里面中,所有的其他标签都写到根标签内部

<bean>标签:
     bean代表要托管的一个类,spring把所有要托管的类都看做是一个bean;
     id属性: bean的id属性不能够重名,具有唯一性。,否则会报错。
          一般情况下,id就认为写成我们之前写的接收创建出来的对象的变量名即可。如userService
     scope属性:工厂默认创建实例是单例模式singleton;多例:scope="prototype"

四、Spring实例化方式

1. 采用无参构造方式实例化(重要:常用)

默认spring实例化某一个类,调用的是该类的无参构造方法, 所以要实例化的类,需要提供无参构造。

        public class UserServiceImpl implements UserService {

            public UserServiceImpl() {
            }

            @Override
            public void save() {
                System.out.println("调用了UserServiceImpl 的 save方法");
            }

        }

配置:

<bean id="us" class="com.xxx.service.impl.UserServiceImpl" scope="prototype"></bean>

2. 采用静态工厂方法实例化

工厂类:
注意不要忘记将获得bean的方法声明成为静态

            public class StaticFactory {


                public static UserService getBean(){
                    return new UserServiceImpl();
                }
            }

配置:

<!-- 以下是静态工厂实例化方式配置
    这种方式要求,我们自己维护工厂,这太复杂了,第一种无参的方式,是spring自己维护工厂。
    class : 指定工厂的位置
    factory-method : 指定工厂的方法。
一旦我们拿着us 去问 spring的工厂要东西。 spring的工厂就会找到我们的工厂,由于我门的工厂方法也是静态的。并且也根据factory-method 属性告诉spring方法叫什么了。 所以spring直接来调用那个静态方法返回对象。现在看上去,创建这个类的实例工作,并不是spring来做。  spring只不过是一个中间人,来调用我的工厂方法而已。
 -->

<bean id="us" class="com.xxx.factory.StaticFactory" factory-method="getBean"></bean>

3. 采用实例化工厂方法获取实例

工厂:

        public class InstanceFactory {

            public UserService  getBean(){
                return new UserServiceImpl();
            }
        }

配置:

我们必须让spring来实例化这个工厂,然后以后我们拿着us 问spring要东西的时候
它就去找刚才它做出来的那个工厂实例,然后调用getBean方法 返回对象。

<bean id="factory" class="com.xxx.factory.InstanceFactory"></bean>
<bean id="us" factory-bean="factory" factory-method="getBean"></bean>

不管是静态工厂还是实例化工厂,都有一个共同点,就是创建实例的工作还是我们自己来做,并且我们要维护自己的工厂。spring的工厂只不过是做一个跳转的作用而已。 所以后面两种方式(使用静态工厂方法获得实例、采用实例工厂方法获得实例) 几乎不会用。


五、注入 - Dependency Injection

注入的简称是DI , 全称是 dependency Injection 翻译过来是依赖注入。

  • 什么是依赖注入

依赖注入其实指的就是我们的某些类里面有成员属性, 要求在创建这个类的实例同时,完成这些成员属性的赋值工作。但是现在创建实例的工作不是我们来做,是spring来做。说的通俗一点,注入其实就是告诉spring在创建实例的时候,把这些成员属性也给赋值。

1. 采用构造方法注入

        public class UserServiceImpl implements UserService {

            private String address;

            public UserServiceImpl(String address) {
                super();
                this.address = address;
            }

            @Override
            public void save() {
                System.out.println("调用了UserServiceImpl的save方法==" + address);
            }
        }

配置:

<bean id="us" class="com.xxx.service.impl.UserServiceImpl" scope="prototype">

<!-- 由于UserServiceImpl 有一个属性叫做 name , 我们还采用了构造方法赋值。 但是到底赋什么值, 我们也需要告诉sprig -->
<constructor-arg name="address" value="奥巴马"></constructor-arg>
<constructor-arg name="password" value="123"></constructor-arg>

</bean>

2. 采用set方法注入(重要 - 常用)

1.字符串类型
bean:需要提供set方法
            private String address;
            public void setAddress(String address) {
                this.address = address;
            }

配置:

<bean id="us" class="com.xxx.service.impl.UserServiceImpl" scope="prototype">
        <property name="address" value="深圳"></property>
</bean>
2. 注入数组
        private String []address;

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

配置:

            <bean id="us" class="com.xxx.service.impl.UserServiceImpl" scope="prototype">
              <property name="address">
                  注入数组数据
                  <array>
                      <value>北京1</value>
                      <value>北京2</value>
                      <value>北京3</value>
                      <value>北京4</value>
                  </array>
              </property>
          </bean>
3. 注入list
        private List<String> address;

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

配置:

<bean id="us" class="com.XXX.service.impl.UserServiceImpl" scope="prototype">
     <property name="address">
            <list>
                              <value>北京11</value>
                              <value>北京22</value>
                              <value>北京33</value>
                              <value>北京44</value>
            </list>
      </property>
 </bean>
4. map
       private Map<String , String> address;

        public void setAddress(Map<String, String> address) {
            this.address = address;
        }

配置:

<bean id="us" class="com.xxx.service.impl.UserServiceImpl" scope="prototype">
      <property name="address">
                      <map>
                          <entry key="地址1" value="北京1"></entry>
                          <entry key="地址2" value="北京2"></entry>
                          <entry key="地址3" value="北京3"></entry>
                          <entry key="地址4" value="北京4"></entry>
                      </map>
      </property>
</bean>
5.对象

类:

        public class UserServiceImpl implements UserService {

            private UserDao userDao  ;

            public void setUserDao(UserDao userDao) {
                this.userDao = userDao;
            }

            @Override
            public void save() {
                System.out.println("调用了UserServiceImpl 的 save方法====" );

                userDao.save();
            }
        }

配置

<!-- 因为要告诉spring一会注入的是这个类的实例,所以必须在这里声明这个bean -->
<bean id="userDao" class="com.xxx.dao.impl.UserDaoImpl"></bean>

<bean id="userService" class="com.xxx.service.impl.UserServiceImpl" scope="prototype">
     <property name="userDao" ref="userDao"></property>
</bean>

3. 采用名称空间 & Spring EL 属性注入

使用名称空间注入需要加入一行配置:
这一行配置可以去官方给的网页资源里面去找到的

<?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:p="http://www.springframework.org/schema/p"
      xmlns:c="http://www.springframework.org/schema/c"
      xsi:schemaLocation=" http://www.springframework.org/schema/beans
     http://www.springframework.org/schema/beans/spring-beans.xsd ">


</beans>
  • c名称空间
    走构造函数的方式进行数据注入,需要提供对应的构造方法
     <bean id="userService" class="com.xxx.service.impl.UserServiceImpl"
           scope="singleton" c:username="ceshi" c:password="123">
      </bean>
  • p名称空间
    走set方法进行数据注入,需要提供对应的set方法
      <bean id="userService" class="com.xxx.service.impl.UserServiceImpl"
           scope="singleton" p:username="ceshi" p:password="123">
      </bean>
  • spring EL 表达式注入
    这种方式需要提供无参数的构造函数
      <bean id="userService" class="com.xxx.service.impl.UserServiceImpl"
           scope="singleton">
           <property name="username" value="#{'测试22'}"></property>
           <property name="password" value="#{'112233'}"></property>
      </bean>

          <bean id="us" class="com.xxx.service.impl.UserServiceImpl" >
                  <property name="address"  value="#{1>2}"/>
          </bean>

整合Servlet和Spring的简单实例:

servlet代码:

public class ServletTest extends HttpServlet {
      private static final long serialVersionUID = 1L;

      @SuppressWarnings("resource")
      protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
           System.out.println("执行了doget方法");

           ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");

           UserService userService = (UserService) applicationContext.getBean("userService");

           userService.save();
           //((AbstractApplicationContext) applicationContext).close();
      }
}

这段代码的问题:
1)每次来一个请求,都会执行doget方法,每次执行doget方法都会创建ClassPathXmlApplicationContext这个类的实例。
2)工厂实例创建的实际稍微晚了。因为请求来了才创建工厂。我们其实可以让工厂的创建稍微提前一点。

改进:
1)要想用监听器,得导入一个spring的jar包中的包:spring-web-4.2.9的包;
2)配置监听器:在web.xml中

  <listener>
      <!-- 配置了这个监听器就可以感知到servletContext被创建,一旦感知到servletContext被创建,就知道项目已经被部署了,
      那么这个监听器就会解析xml,然后立即创建工厂 -->
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

  <!-- 告诉spring,我们的xml配置文件在哪里
  classpath:applicationContext.xml就是告诉spring要到类路径去找这个文件 -->
  <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:applicationContext.xml</param-value>
  </context-param>

3)生成工厂:

      @SuppressWarnings("resource")
      protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
           System.out.println("执行了doget方法");

           WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(getServletContext());

           UserService userService = (UserService) context.getBean("userService");

           userService.save();

      }

工厂创建的时候,创建之后会把工厂放到servletcontext作用域中去,所以可以这样取:
可以看看源码,上面一种方法的背后也是使用下面这种方式来取值的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值