Loading

Spring(一)简介和配置

知识补充:

那么什么是xmlns呢?xmlns其实是XML Namespace的缩写,可译为“XML命名空间”,但个人觉得,翻译后的名字反而不好理解,所以我们就叫它为XML Namespace吧。

考虑这样两个XML文档:表示HTML表格元素的<table/>:

1

2

3

4

5

6

<table>

  <tr>

    <td>Apples</td>

    <td>Bananas</td>

  </tr>

</table>

    和描述一张桌子的<table/>:

1

2

3

4

5

<table>

  <name>African Coffee Table</name>

  <width>80</width>

  <length>120</length>

</table>

假如这两个 XML 文档被一起使用,由于两个文档都包含带有不同内容和定义的 <table> 元素,就会发生命名冲突。XML 解析器是无法确定如何处理这类冲突。为了解决上述问题,xmlns就产生了。

如何使用xmlns?

    很简单,使用语法: xmlns:namespace-prefix="namespaceURI"。其中namespace-prefix为自定义前缀,只要在这个XML文档中保证前缀不重复即可;namespaceURI是这个前缀对应的XML Namespace的定义。例如,

xmlns:context="http://www.springframework.org/schema/context"

这一句定义了一个http://www.springframwork.org/schema/context的Namespace(这和Java类中的包的声明很相似),并将其和前缀context绑定。所以上面的Spring XML文档中会有这么一句:

<context:component-scan base-package="xxx.xxx.controller" />

   这里的<component-scan/>元素就来自别名为context的XML Namespace,也就是在http://www.springframework.org/schema/context中定义的。

   我们还可以将前缀定义为abc:

xmlns:abc="namespaceURI"

但是, 在一个拥有众多元素的文档中, 仅仅拥有前缀, 也不能完全避免命名冲突的问题。

  • 注意 xml 文档相互之间是可以通过 XInclude, External Entites 实现相互包含或者引用的。

此时, 命名空间就诞生了, 我们可以为元素定义一个命名空间, 将一个很长的, 可以保证全局唯一性的字符串与该元素关联起来。这样就可以避免命名冲突了。

但是如何保证那个较长的字符串全局唯一呢, 最好的方式莫过于使用 统一资源标识符(Uniform Resource Identifier,URI) 了, 而我们最常见的 URI 就是平时经常访问的网址 URL 了。

xmlns:namespace-prefix="namespaceURI"

 对于命名空间的标识符, URI 的作用仅仅是保证唯一性, 它并不需要对应一个可以访问的资源或文件 ! 但是, 有很多公司都会让 namespace 的 URI 指向一个包含该命名空间信息的网页

回到我们的 POM 文档头中,你会发现 project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 中的http://www.w3.org/2001/XMLSchema-instance可以访问到一个正常的页面, 但是如果访问 xmlns="http://maven.apache.org/POM/4.0.0" 中的 http://maven.apache.org/POM/4.0.0 就会得到一个 PAGE NOT FOUND 错误, 页面未获取到。

xmlns和xmlns:xsi有什么不同?

    xmlns表示默认的Namespace。例如Spring XML文档中的

xmlns="http://www.springframework.org/schema/beans"

这一句表示该文档默认的XML Namespace为http://www.springframwork.org/schema/beans。对于默认的Namespace中的元素,可以不使用前缀。例如Spring XML文档中的

<bean id="xxx" class="xxx.xxx.xxx.Xxx">
  <property name="xxx" value="xxxx"/>
</bean>

  xmlns:xsi表示使用xsi作为前缀的Namespace,当然前缀xsi需要在文档中声明。

 xsi:schemaLocation有何作用

    xsi:schemaLocation属性其实是Namespace为http://www.w3.org/2001/XMLSchema-instance里的schemaLocation属性,正是因为我们一开始声明了

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

这里才写作xsi:schemaLocation(当然一般都使用这个前缀)。它定义了XML Namespace和对应的XSD(Xml Schema Definition)文档的位置的关系。它的值由一个或多个URI引用对组成,两个URI之间以空白符分隔(空格和换行均可)。第一个URI是定义的XML Namespace的值,第二个URI给出Schema文档的位置,Schema处理器将从这个位置读取Schema文档,该文档的targetNamespace必须与第一个URI相匹配。例如:

xsi:schemaLocation="http://www.springframework.org/schema/context 
                    http://www.springframework.org/schema/context/spring-context.xsd"

 根据之前的知识我们可以理解, xmlns:xsi 定义了一个命名空间前缀 xsi 对应的唯一字符串 http://www.w3.org/2001/XMLSchema-instance。 但是读者会发现, 这个 xmlns:xsi 在不同的 xml 文档中似乎都会出现。 这是因为, xsi 已经成为了一个业界默认的用于 XSD((XML Schema Definition) 文件的命名空间。 而 XSD 文件(也常常称为 Schema 文件)是用来定义 xml 文档结构的。

1. spring概述

1.1 Spring是什么(理解)

Spring是分层的 Java SE/EE应用 full-stack 轻量级开源框架,以 IoC(Inverse Of Control:反转控制)和 AOP(Aspect Oriented Programming:面向切面编程)为内核。

提供了展现层 SpringMVC和持久层 Spring JDBCTemplate以及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多著名的第三方框架和类库,逐渐成为使用最多的Java EE 企业应用开源框架

三层架构     

  • A 表现层   web层    MVC是表现层的一个设计模型 
  • B 业务层  service层
  • C 持久层  dao层

1.2 Spring发展历程 (了解)

EJB

Rod Johnson ( Spring 之父)

2017 年 9 月份发布了 Spring 的最新版本 Spring5.0 通用版(GA)

1.3 Spring的优势(理解)

1)方便解耦,简化开发

2)AOP 编程的支持

3)声明式事务的支持

4)方便程序的测试

1.4 Spring的体系结构(了解)

  • spring-core模块提供了框架的基本组成部分,包括 IoC 和依赖注入功能。

  • spring-beans 模块提供 BeanFactory,工厂模式的微妙实现,它移除了编码式单例的需要,并且可以把配置和依赖从实际编码逻辑中解耦。

  • context模块建立在由core和 beans 模块的基础上建立起来的,它以一种类似于JNDI注册的方式访问对象。Context模块继承自Bean模块,并且添加了国际化(比如,使用资源束)、事件传播、资源加载和透明地创建上下文(比如,通过Servelet容器)等功能。Context模块也支持Java EE的功能,比如EJB、JMX和远程调用等。ApplicationContext接口是Context模块的焦点。spring-context-support提供了对第三方库集成到Spring上下文的支持,比如缓存(EhCache, Guava, JCache)、邮件(JavaMail)、调度(CommonJ, Quartz)、模板引擎(FreeMarker, JasperReports, Velocity)等。

  • spring-expression模块提供了强大的表达式语言,用于在运行时查询和操作对象图。它是JSP2.1规范中定义的统一表达式语言的扩展,支持set和get属性值、属性赋值、方法调用、访问数组集合及索引的内容、逻辑算术运算、命名变量、通过名字从Spring IoC容器检索对象,还支持列表的投影、选择以及聚合等。

 

2. spring快速入门

2.1 Spring程序开发步骤

①导入 Spring 开发的基本包坐标

②编写 Dao 接口和实现类

③创建 Spring 核心配置文件

④在 Spring 配置文件中配置 UserDaoImpl

⑤使用 Spring 的 API 获得 Bean 实例对象

2.2 导入Spring开发的基本包坐标

1、创建一个maven项目

新建一个文件夹spring

file-open-spring

new-module-Maven-next-name:com.itheima、itheima_spring_aop-next-finsih

file-projectstructure-Project设置apply-facets-web-itheima_spring_aop-改路径webapp到main下

2、

出现版本的bug需要在pom.xml文件中加入一段代码

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>13</source>
                <target>13</target>
            </configuration>
        </plugin>
    </plugins>
  </build>

导入spring坐标

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

2.3 编写Dao接口和实现类

package com.itheima.dao;

public interface UserDao {
    public void save();
}
package com.itheima.dao.impl;

import com.itheima.dao.UserDao;

public class UserDaoImpl implements UserDao {
    public void save() {
        System.out.println("save running...");
    }
}

2.4 创建Spring核心配置文件

在类路径下(resources)创建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">
</beans>

2.5 在Spring配置文件中配置UserDaoImpl

配置UserDaoImpl

<?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="userDao" class="com.itheima.dao.impl.UserDaoImpl"></bean>
</beans>

 

2.6 使用Spring的API获得Bean实例

package com.itheima.demo;

import com.itheima.dao.UserDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class UserDaoDemo {
    public static void main(String[] args) {
        ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserDao userDao = (UserDao) app.getBean("userDao");
        userDao.save();
    }
}

2.7 知识要点

3. Spring配置文件

3.1 Bean标签基本配置

用于配置对象交由Spring 来创建。

默认情况下它调用的是类中的无参构造函数,如果没有无参构造函数则不能创建成功。

基本属性:

id:Bean实例在Spring容器中的唯一标识

class:Bean的全限定名称

 

<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"></bean>

3.2 Bean标签范围配置  

scope:指对象的作用范围,取值如下:

取值范围说明
singleton默认值,单例的
prototype多例的(多个对象)
requestWEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 request 域中
sessionWEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 session 域中
global sessionWEB 项目中,应用在 Portlet 环境,如果没有 Portlet 环境那么globalSession 相当于 session

1)当scope的取值为singleton时

Bean的实例化个数:1个

Bean的实例化时机:当Spring核心文件被加载时,实例化配置的Bean实例

Bean的生命周期:

  • 对象创建:当应用加载配置文件,创建容器时,对象就被创建了
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
  • 对象运行:只要容器在,对象一直活着
  • 对象销毁:当应用卸载,销毁容器时,对象就被销毁了

2)当scope的取值为prototype时

Bean的实例化个数:多个

Bean的实例化时机:当调用getBean()方法时实例化Bean

  • 对象创建:当使用对象时getBean,创建新的对象实例
UserDao userDao1 = (UserDao) app.getBean("userDao");
  • 对象运行:只要对象在使用中,就一直活着
  • 对象销毁:当对象长时间不用时,被 Java 的垃圾回收器回收了
 <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl" scope="singleton"></bean>
package com.itheima.test;

import com.itheima.dao.UserDao;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringTest {
    @Test
    public  void test1(){
        ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserDao userDao1 = (UserDao) app.getBean("userDao");
        UserDao userDao2 = (UserDao) app.getBean("userDao");
        System.out.println(userDao1);
        System.out.println(userDao2);
    }
}

输出结果,只存在一个

C:\wusier\study\jdk-13.0.2_windows-x64_bin\jdk-13.0.2\bin\java.exe -ea -
com.itheima.dao.impl.UserDaoImpl@158da8e
com.itheima.dao.impl.UserDaoImpl@158da8e

Process finished with exit code 0

用prototype就是不同的对象

<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl" scope="prototype"></bean>
C:\wusier\study\jdk-13.0.2_windows-x64_bin\jdk-13.0.2\bin\java.exe -ea -
com.itheima.dao.impl.UserDaoImpl@61862a7f
com.itheima.dao.impl.UserDaoImpl@441772e

Process finished with exit code 0

3.3 Bean生命周期配置

init-method:指定类中的初始化方法名称

destroy-method:指定类中销毁方法名称

要配置告诉spring方法自己的初始化和销毁

<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl" init-method="init" destroy-method="destroy"></bean>

先创建再初始化 

 

手动关闭 

3.4 Bean实例化三种方式

1) 使用无参构造方法实例化

它会根据默认无参构造方法来创建类对象,如果bean中没有默认无参构造函数,将会创建失败

<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"></bean>

2) 工厂静态方法实例化

工厂的静态方法返回Bean实例

public class StaticFactoryBean {
    public static UserDao getUserDao(){    
    return new UserDaoImpl();
    }
}
    <bean id="userDao" class="com.itheima.factory.StaticFactory" factory-method="getUserDao"></bean>

3) 工厂实例方法实例化

工厂的非静态方法返回Bean实例

public class DynamicFactoryBean {  
    public UserDao getUserDao(){        
        return new UserDaoImpl(); 
    }
}
<bean id="factory" class="com.itheima.factory.DynamicFactory"></bean> //创建工厂对象
<bean id="userDao" factory-bean="factory" factory-method="getUserDao"/> //调用工厂对象的方法

3.5 Bean的依赖注入入门

①创建 UserService,UserService 内部在调用 UserDao的save() 方法

package com.itheima.service.impl;

import com.itheima.dao.UserDao;
import com.itheima.service.UserService;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class UserServiceImpl implements UserService {
    @Override
    public void save() {
        ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserDao userDao = (UserDao) app.getBean("userDao");
        userDao.save();
    }
}

②将 UserServiceImpl 的创建权交给 Spring

<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"></bean>
<bean id="userService" class="com.itheima.service.impl.UserServiceImpl"></bean>

③从 Spring 容器中获得 UserService 进行操作

public class UserController {
    public static void main(String[] args) {
        ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = (UserService) app.getBean("userService");
        userService.save();

    }
}

只操作service

3.6 Bean的依赖注入概念

 

容器内部进行注入 

  

依赖注入(Dependency Injection):它是 Spring 框架核心 IOC 的具体实现。

在编写程序时,通过控制反转,把对象的创建交给了 Spring,但是代码中不可能出现没有依赖的情况。

IOC 解耦只是降低他们的依赖关系,但不会消除。例如:业务层仍会调用持久层的方法。

那这种业务层和持久层的依赖关系,在使用 Spring 之后,就让 Spring 来维护了。

简单的说,就是坐等框架把持久层对象传入业务层,而不用我们自己去获取

3.7 Bean的依赖注入方式

①构造方法

创建有参构造

public class UserServiceImpl implements UserService {
    private UserDao userDao;

    public UserServiceImpl(UserDao userDao) {
        this.userDao = userDao;
    }

    public UserServiceImpl() {
    }

    //    public void setUserDao(UserDao userDao) {
//        this.userDao = userDao;
//    }
    @Override
    public void save() {
        userDao.save();
    }
}

配置Spring容器调用有参构造时进行注入

第一个userDao是构造方法的参数名


    <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"></bean>

    <bean id="userService" class="com.itheima.service.impl.UserServiceImpl">
            <constructor-arg name="userDao" ref="userDao"></constructor-arg>
    </bean>

②set方法

Dao注入service
 1、在UserServiceImpl中添加setUserDao方法

2、配置Spring容器调用set方法进行注入

public class UserServiceImpl implements UserService {
    private UserDao userDao;
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;  
        } 
    @Override    
    public void save() {      
   	    userDao.save();
	}
}

 配置Spring容器调用set方法进行注入

第一个userDao是service对应的属性名

    <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"></bean>

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

直接调用的话,new service没有用,因为没有new Dao,只有spring的配置文件可以生成对象实例,所以会出现空指针

P命名空间 

xmlns:p="http://www.springframework.org/schema/p"
    <bean id="userService" class="com.itheima.service.impl.UserServiceImpl" p:userDao-ref="userDao"/>

 

3.8 Bean的依赖注入的数据类型

上面的操作,都是注入的引用Bean,处了对象的引用可以注入,普通数据类型,集合等都可以在容器中进行注入。

注入数据的三种数据类型

普通数据类型

引用数据类型

集合数据类型

其中引用数据类型,此处就不再赘述了,之前的操作都是对UserDao对象的引用进行注入的,下面将以set方法注入为例,演示普通数据类型和集合数据类型的注入。

Bean的依赖注入的数据类型

(1)普通数据类型的注入

public class UserDaoImpl implements UserDao {
private String company;
    private int age;
    public void setCompany(String company) {
        this.company = company;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public void save() {
        System.out.println(company+"==="+age);
        System.out.println("UserDao save method running....");   
    }
}
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl">
    <property name="company" value="传智播客"/>
    <property name="age" value="15"/>
</bean>

(2)集合数据类型(List<String>)的注入

public class UserDaoImpl implements UserDao {
	private List<String> strList;
	public void setStrList(List<String> strList) {
		this.strList = strList;
	}
	public void save() {
        System.out.println(strList);
        System.out.println("UserDao save method running....");
	}
}
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl">
    <property name="strList">
        <list>
            <value>aaa</value>
            <value>bbb</value>
            <value>ccc</value>
        </list>
    </property>
</bean>

(3)集合数据类型(List<User>)的注入

public class UserDaoImpl implements UserDao {
	private List<User> userList;
	public void setUserList(List<User> userList) {
	this.userList = userList;  
 }
public void save() {
	System.out.println(userList);
	System.out.println("UserDao save method running....");
	}
}

 

<bean id="u1" class="com.itheima.domain.User"/>
<bean id="u2" class="com.itheima.domain.User"/>
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl">
    <property name="userList">
        <list>
            <bean class="com.itheima.domain.User"/>
            <bean class="com.itheima.domain.User"/>
            <ref bean="u1"/>
            <ref bean="u2"/>       
        </list>
    </property>
</bean>

(4)集合数据类型( Map<String,User> )的注入

public class UserDaoImpl implements UserDao {
    private Map<String,User> userMap;
    public void setUserMap(Map<String, User> userMap) {
    this.userMap = userMap;
    }    
public void save() {      
	System.out.println(userMap);
	System.out.println("UserDao save method running....");
	}
}

 

<bean id="u1" class="com.itheima.domain.User"/>
<bean id="u2" class="com.itheima.domain.User"/>
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl">
    <property name="userMap">
        <map>            
            <entry key="user1" value-ref="u1"/>
            <entry key="user2" value-ref="u2"/>
        </map>
    </property>
</bean>

(5)集合数据类型(Properties)的注入

public class UserDaoImpl implements UserDao {
    private Properties properties;
    public void setProperties(Properties properties) {
        this.properties = properties;
    }
	public void save() {
		System.out.println(properties);
		System.out.println("UserDao save method running....");
	}
}
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl">
    <property name="properties">
        <props>
            <prop key="p1">aaa</prop>
            <prop key="p2">bbb</prop> 
            <prop key="p3">ccc</prop>
        </props>
    </property>
</bean>

3.9 引入其他配置文件(分模块开发)

实际开发中,Spring的配置内容非常多,这就导致Spring配置很繁杂且体积很大,所以,可以将部分配置拆解到其他配置文件中,而在Spring主配置文件通过import标签进行加载

<import resource="applicationContext-xxx.xml"/>

总结

需要好好背会

4. spring相关API

4.1 ApplicationContext的继承体系

applicationContext:接口类型,代表应用上下文,可以通过其实例获得 Spring 容器中的 Bean 对象

 

4.2 ApplicationContext的实现类

1)ClassPathXmlApplicationContext

它是从类的根路径下加载配置文件 推荐使用这种

2)FileSystemXmlApplicationContext

它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置,需要磁盘地址,绝对路径。

3)AnnotationConfigApplicationContext

当使用注解配置容器对象时,需要使用此类来创建 spring 容器。它用来读取注解。

 

4.3 getBean()方法使用

源码

public Object getBean(String name) throws BeansException {  
    assertBeanFactoryActive();   
    return getBeanFactory().getBean(name);
}
public <T> T getBean(Class<T> requiredType) throws BeansException {   			    	        
    assertBeanFactoryActive();
    return getBeanFactory().getBean(requiredType);
}

 

其中,当参数的数据类型是字符串时,表示根据Bean的id从容器中获得Bean实例,返回是Object,需要强转。

当参数的数据类型是Class类型时,表示根据类型从容器中匹配Bean实例,当容器中相同类型的Bean有多个时,则此方法会报错

getBean()方法使用

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
  UserService userService1 = (UserService) applicationContext.getBean("userService");//方法存在多个对象使用这个一
  UserService userService2 = applicationContext.getBean(UserService.class);//方法二存在单个对象简易使用

 

posted @ 2020-07-27 12:30  kopoo  阅读(127)  评论(0)    收藏  举报