2.Spring核心容器

spring核心容器

包装,装载物品 的贮存器

web服务器实际是动态网页程序文件的容器

lib下的包

 
commons-loggin.jar
junit-4.8.2.jar
spring-aop-4.1.0.RELEASE.jar
spring-beans-4.1.0.RELEASE.jar
spring-context-4.1.0.RELEASE.jar
spring-core-4.1.0.RELEASE.jar
spring-expression-4.1.0.RELEASE.jar

spring核心容器概述

spring容器提供了:IOC机制

IOC(Inversion Of Control)

控制反转,通过容器来控制对象的创建和维护,对象中成员变量的创建及维护

反转就是将对象的控制权转移给容器处理,目的是获得更好的扩展性和可维护性

 public class Boy{
     private Dog dog;
     public Dog getDog(){
         return dog;
    }
     public void setDog(Dog dog){
         this.dog = dog;
    }
 }
 ​
 public class Dog{
     private String dogName;
     public String getDogName(){
         return dogName;
    }
     public void setDogName(String dogName){
         this.dogName = dogName;
    }
 }
 //传统的对象创建和维护方式
 Dog dog = new Dog();
 dog.setName("来福");
 Boy boy = new Boy();
 boy.setDog(dog);
 ​
 //采用IOC来创建和维护对象的方式(模拟),对象中的依赖关系,也依赖于容器处理
 容器 a = new 容器();
 Boy boy = a.get(); //a.getBean();

spring核心容器

核心容器时spring框架的核心

用户编写的程序文件发布到服务器之后,由spring负责管理,包含对象的初始化,函数的调用,对象的消亡等

可以将spring看作是服务器与应用程序的中间管理组件

 

通过代码理解spring怎么控制反转

导入包spring核心容器相关包

普通java类建立

spring配置文件

通过spring内置的API接口初始化spring容器,获取spring容器管理java类的实例

1.在项目文件夹下,创建lib文件夹,把包复制到lib下,全部build path
2.创建普通java类
 public class Dog{
     public void eat(){
  System.out.println("小狗吃粑粑");
    }
 }
3.创建spring配置文件(框架阶段,配置文件很重要,经常需要配置配置文件)

创建在软件包里

applicationContext.xml spring配置文件专属名称

spring需要头文件

<?xml version="1.0" encoding="utf-8"> 版本与编码(第一行)

 <!-- spring配置文件 -->
 <!-- 第一行:命名空间
  第二行:标签规范
  第三行:前半部分命名空间,后半部分xml的schema约束文件路径-->
 <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="dog" class="com.icss.vo.Dog"></bean>
 </beans>
4.代码测试

通过spring内置API接口初始化spring容器,并获取spring容器管理Java类的实例

接口类型:ApplicationContext

 public class Test{
     public static void main(String[] args){
         new Test().testContext();
    }
     public void testContext(){
         // . 改成 /
         //初始化一个spring容器
         String str = "com/icss/test/applicationContext.xml";
         ApplicationContext ac = new ClassPathXmlApplicationContext(str);
         //有了这个容器我就可以和这个容易要一个dog对象,不再需要实例化dog对象了
         //参数就是spring配置文件
         Dog dog = (Dog)ac.getBean("dog");
         dog.eat();
    }
 }

bean的实例化

创建或获得某个类的对象

bean的实例化方式

构造器方式(无参构造器方式,有参构造器方式) 静态工厂方式 普通工厂方式 定义多个配置文件方法

spring的默认情况下是调用java类的构造器进行初试化的
无参构造器构造
 public Dog(){
  System.out.println("无参构造");
 }
 <bean id="dog" class="com.icss.vo.Dog"></bean>
有参构造方法
 public Dog(String name,int age){
  System.out.println("有参构造");
     this.name = name;
     this.age = age;
 }

constructor-arg标签:设置初始化bean的构造方法参数

index:构造方法参数位置,从0开始

value:参数值

spring根据constructor-arg标签判断调用哪个构造器初始化对象实例

<bean id="dog" class="com.icss.vo.Dog">
<constructor-arg index="0" value="藏獒"></constructor-arg>
<constructor-arg index="1" value="5"></constructor-arg>
</bean>
调用
public class Test{
public static void main(String[] args){
new Test().testContext();
}
public void testContext(){
// . 改成 /
//初始化一个spring容器
String str = "com/icss/test/applicationContext.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(str);
//有了这个容器我就可以和这个容易要一个dog对象,不再需要实例化dog对象了
//参数就是spring配置文件

//以下两行为无参构造,四行为有参构造
Dog dog = (Dog)ac.getBean("dog");
dog.eat();
System.out.println(dog.getName());
System.out.println(dog.getAge());
}
}
静态工厂方式

工厂是批量生产的,我们只需要和工厂去要,不需要自己创建对象

工厂类使用静态方法创建对象

public class StaticFactory{
public static Dog getDog(){
return new Dog();
}
}
<bean id="dog1" class="com.icss.factory.StaticFactory" factory-method="getDog"></bean>
调用
public class Test{
public static void main(String[] args){
new Test().testContext();
}
public void testContext(){
// . 改成 /
//初始化一个spring容器
String str = "com/icss/test/applicationContext.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(str);
//有了这个容器我就可以和这个容易要一个dog对象,不再需要实例化dog对象了
Dog dog = (Dog)ac.getBean("dog1");
dog.eat();
}
}
普通工厂方式

需要初始化工厂类实例,通过执行工厂类的方法创建产品对象返回并引用

public class DogFactory{
public Dog getDog(){
return new Dog();
}
}
<bean id="DogFactory" class="com.icss.factory.DogFactory"></bean>
<bean id="dog2" factory-bean="DogFactory" factory-method="getDog"></bean>
调用
public class Test{
public static void main(String[] args){
new Test().testContext();
}
public void testContext(){
// . 改成 /
//初始化一个spring容器
String str = "com/icss/test/applicationContext.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(str);
//有了这个容器我就可以和这个容易要一个dog对象,不再需要实例化dog对象了
Dog dog = (Dog)ac.getBean("dog2");
dog.eat();
}
}

定义多个配置文件

spring提供import标签,可以在一个配置文件中引入其他spring配置文件

<!-- 和主配置文件applicationContext.xml在同一目录下 -->
<import resource="/applicationContext1.xml"/>

resource值只能为引入配置文件的相对路径(相对于主配置文件)

bean的管理

bean的作用域:组件bean的有效时间,通过配置文件设定

<bean id="dog" class="com.icss.vo.Dog" scope="singleton" lazy-init="true"></bean>

Spring IOC 容器中,仅存在一个Bean实例,Bean以单实例的方式存在

lazy-init 初始化时间延迟加载

scope的取值

singleton prototype session globalSession request

当 scope="prototype":多实例,每次获取对象实例时(getBean())spring都会创建一个对象实例

当 scope="singleton" :单实例,spring容器只创建一个对象实例。根据bean标签的 lazy-init 属性值选择创建时间

lazy-init 取值范围 true/false 默认false

true:延迟加载,当第一次获取对象实例时创建对象(调用getBean()时)

false:不会延迟加载,容器加载时创建对象(创建容器对象的同时就会调用构造方法创建对象)

代码测试 scope="prototype"
<bean id="dog" class="com.icss.vo.Dog" scope="prototype"></bean>
Dog dog1 = (Dog)ac.getBean("dog");
Dog dog2 = (Dog)ac.getBean("dog");
dog1.eat();
dog2.eat();
输出结果:

无参构造

无参构造

小狗吃粑粑

小狗吃粑粑

代码测试 scope="singleton"
<bean id="dog" class="com.icss.vo.Dog" scope="singleton"></bean>
Dog dog1 = (Dog)ac.getBean("dog");
Dog dog2 = (Dog)ac.getBean("dog");
dog1.eat();
dog2.eat();
输出结果:

无参构造

小狗吃粑粑

小狗吃粑粑

bean的初始化方法和销毁方法

spring在创建bean实例后,调用bean的初始化方法

spring在容器关闭后,bean不被spring容器调用,进入垃圾可回收阶段,在容器关闭之前会调用bean的销毁方法

只有 scope="singleton" 的bean才会执行销毁方法

<bean id="dog" class="com.icss.vo.Dog" scope="singleton"
init-method="initTest" destroy-method="destroyTest">
<constructor-arg index="0" value="藏獒"></constructor-arg>
<constructor-arg index="1" value="5"></constructor-arg>
</bean>
public void initTest(){
System.out.println("初始化方法");
}
public void destroyTest(){
System.out.println("销毁方法");
}
spring的初始化方法调用时间 创建对象之后
spring的销毁方法调用时间 容器关闭之前
String str = "com/icss/test/applicationContext.xml";
//ApplicationContext没有close()方法
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext(str);
Dog dog = (Dog)ac.getBean("dog");
dog.eat();
ac.close();
输出结果:

有参构造

初始化方法

小狗吃粑粑

销毁方法

 

bean的属性设置

依赖注入(DI,类似于赋值的意思,对属性赋值)

spring容易不仅可以初始化对象,也可以对对象当中的成员变量赋值

初始化成员变量以及其赋值过程,不需手动编码,由spring容器去做

这种依赖容器初始化对象,并赋值给bean全局变量的方式叫依赖注入

依赖注入的方式
自动匹配

自动装配 byName,byType,construct or

手动注入 (基本类型(8种),组件bean,集合、map)

构造方法

setter方法(属性注入)

一般建议手动注入,不会产生不确定性

public class Test{
//基本数据类型
private String name;
private int age;
//组件bean
private Dog dog;
//集合 list
private List list;
}

手动注入

setter方法注入
1.基本类型注入

泛指:当前bean组件的属性为基本类型,基本类型的封装类型,String,StringBuffer,容器可以读取配置文件对当前属性进行赋值

spring DI

public class Dog{
private String name;
private int age;
public void setName(String name){
this.name = name;
}
public void setAge(int age){
this.age = age;
}
public String getName(){
return name;
}
public int getAge(){
return age;
}
}
<bean id="dog" class="com.icss.vo.Dog">
<property name="name" value="京巴"></property>
<property name="age" value="2"></property>
</bean>
Dog dog = (Dog)ac.getBean("dog");
System.out.println(dog.getName());
System.out.println(dog.getAge());
输出结果:

无参构造

京巴

2

2.spring组件类型注入

当前bean组件的属性为spring容器的其他bean组件,容器可以读取配置文件对当前属性进行赋值

public class Boy{
private String name;
private Dog dog;
public void setName(String name){
this.name = name;
}
public void setDog(Dog dog){
this.dog = dog;
}
public String getName(){
return name;
}
public Dog getDog(){
return dog;
}
}
<bean id="boy" class="com.icss.vo.Boy">
<property name="name" value="小明"></property>
<property name="dog" ref="dog"></property>
</bean>
Boy boy = (Boy)ac.getBean("boy");
System.out.println(boy.getName());
System.out.println(boy.getDog().getName());
System.out.println(boy.getDog().getAge());
输出结果:

无参方法(Dog)

小明

京巴

2

内部bean(不建议使用,缺点:外部的其他bean组件无法访问)

3.集合类型注入

泛指:当前bean组件的属性为Set,List,Map,数组,Properties等

List注入方式

<bean id="boy" class="com.icss.vo.Boy">
<property name="list">
<list>
<!-- 以下三种形式都可以 -->
<value type="java.lang.String">张三</value>
<ref bean="bean"/>
<null></null>
</list>
</property>
</bean>

list中对象的顺序,按照从上到下的赋值顺序,list当中的数据可以为基本类型、spring组件类型,集合类型等

public class Boy{
private List hob;
public void setHob(List hob){
this.hob = hob;
}
public List getHob(){
return hob;
}
}
<bean id="boy" class="com.icss.vo.Boy">
<property name="hob">
<list>
<value type="java.lang.String">游戏</value>
<value type="java.lang.String">代码</value>
</list>
</property>
</bean>
Boy boy = (Boy)ac.getBean("boy");
List<String> list = boy.getHob();
for(String h:list){
System.out.println(h);
}
输出结果:

游戏

代码

Set注入方式

<bean id="boy" class="com.icss.vo.Boy">
<property name="set">
<set>
<value type="java.lang.String">张三</value>
<ref bean="bean"/>
</set>
</property>
</bean>

set当中的数据可以为基本类型、spring组件类型,集合类型等

public class Boy{
private Set hob;
public void setHob(Set hob){
this.hob = hob;
}
public Set getHob(){
return hob;
}
}
<bean id="boy" class="com.icss.vo.Boy">
<property name="hob">
<set>
<value type="java.lang.String">游戏</value>
<value type="java.lang.String">代码</value>
</set>
</property>
</bean>
Set<String> set = boy.getHob();
for(String h:set){
System.out.println(h);
}

map注入方式

<bean id="boy" class="com.icss.vo.Boy">
<property name="map">
<map>
<entry key-ref="bean" value-ref=""></entry>
<entry key="aa" value="bb"></entry>
</map>
</property>
</bean>

map的key值可以使用key=""去引用基本类型,也可以使用key-ref引用spring组件,value的值类似

//Boy类中
private Map scores;
public void setScores(Map scores){
this.scores=scores;
}
public Map getScores(){
return scores;
}
<bean id="boy" class="com.icss.vo.Boy">
<property name="scores">
<map>
<entry key="javase" value="70"></entry>
<entry key="javaee" value="80"></entry>
<entry key="oracle" value="75"></entry>
</map>
</property>
</bean>
Boy boy = (Boy)ac.getBean("boy");
Map map = boy.getScores();
Iterator it = map.keySet().iterator();
while(it.hasnext()){
String key = (String)it.next();
System.out.println(key + "\t" + map.get(key));
}
输出结果:

javase 70

javaee 80

oracle 75

构造器方式注入

spring初始化组件时,调用含参数的构造器对全局变量进行复制,参数类型可以为基本类型、spring组件类型,集合类型等

赋值方式与setter方式赋值方式一致

<bean id="dog" class="com.icss.vo.Dog">
<constructor-arg index="0" value="二哈" type="java.lang.String"></constructor-arg>
<constructor-arg index="1" value="5"></constructor-arg>
<constructor-arg index="2" ref="beanName"></constructor-arg>
</bean>
自动注入(了解)
<bean id="dog" class="com.icss.vo.Dog" autowire="byType"></bean>

自动装配可以省略<property></property>

autowire属性取值

byType 按类型装配,没找到:属性值为null,找到多个抛异常

byName 按名称装配,没找到:属性值为null

constructo 和byType类似,应用于构造器,找不到相应构造器参数的bean,抛出异常

面向接口编程

接口:在表面上是由几个没有主体代码的方法定义组成的集合体,有唯一的名称,可被类或其他接口所实现(继承)

面向接口编程:在系统分析或架构设计中,每个层级的程序并不是直接提供程序服务,而是定义一组接口

通过实现接口来提供功能

面向接口编程实际是面向对象编程的一部分

接口:interface

静态常量:public static final

抽象方法:没有方法体

 

controller

没有使用面向接口编程

service,dao 由架构师提供接口,程序员实现接口

面向接口编程 — 优点

接口的定义和接口的实现分开

接口可以有多个实现

 

spring项目程序架构

三层架构 五层架构 MVC

三层架构 controller(action)—>(接口)biz(business)—>(接口)dao

三层架构模式是在mvc设计模式上衍生出来的,每个企业的业务需求,企业类库不同,因此架构模式也不同

spring是鼓励企业在后台程序中使用三层架构模式的

案例 (不使用spring,单纯演示三层架构)

三个软件包 com.icss.controller com.icss.service com.icss.dao

dao层和service层分别有一个接口类和一个接口实现类,都有四个方法:增删改查

service: 接口:(public interface)IUserService 接口实现类:(public class)UserServiceImp1

dao: 接口:(public interface)IUserDAO 接口实现类:(public class)UserDAOImp1

service中的代码

public class UserServiceImp1 implements IUserService{
//增删改查
//此处只简写删
public void deleteUser(){
IUserDAO iud = new UserDAOImp1();
iud.deleteUser();
}
}

controller中代码

public class TestController{
public static void main(String[] args){
//通常写法
UserServiceImp1 us = new UserServiceImp1();
//项目开发中写法
IUserService us1 = new UserServiceImp1();
us1.deleteUser();
}
}
使用spring配置文件实现三层架构 (配置文件形式)

第一步

public class UserServiceImp1 implements IUserService{
//增删改查
//此处只简写删
private IUserDAO iud;
public void setIud(IUserDAO iud){
this.iud = iud;
}
public IUserDAO getIud(){
return iud;
}

public void deleteUser(){
iud.deleteUser();
}
}

判断是否需要实例化对象来决定是否写bean

<bean id="UserServiceImp1" class="com.icss.service.UserServiceImp1" scope="singleton">
<property name="iud" ref="UserDAOImp1"/>
</bean>
<bean id="UserDAOImp1" class="com.icss.dao.UserDAOImp1" scope="singleton"></bean>
public class TestController{
public static void main(String[] args){
new TestController().testContext();
}
public void testContext(){
String str = "com/icss/controller/applicationContext.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(str);
IUserService iud = (IUserService)ac.getBean("UserServiceImp1");
iud.deleteUser();
}
}

 

使用注解完成IOC配置

spring3.0之后,引入了组件自动扫描机制

它可以在类路径底下寻找标注了@Component,@Service,@Controller,@Repository注解的类

并把这些类纳入进spring容器管理,他的作用和在xml文件中使用bean节点配置组件是一样的

  
@Component 无法区分类别时使用的注解
@Service 业务层注解
@Controller 控制层注解
@Repository DAO层注解

步骤

1.引入AOP的jar包

2.spring配置文件增加context命名空间和xsd的引用,使用注解需要context组件解析配置文件

3.增加context的动态扫描

<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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.icss.*"></context:component-scan>
</beans>

base-package:为需要扫描的包

注解所有bean

<context:component-scan base-package="com.icss.vo"></context:component-scan>

加注解

//类似于在xml中定义一个bean id是dog
@Component(value="dog")
public class Dog{
@Value(value="小狗狗")
private String name;
@Value(value="2")
private int age;
public void setName(String name){
this.name = name;
}
public void setAge(int age){
this.age = age;
}
public String getName(){
return name;
}
public int getAge(){
return age;
}
}

使用注解配置spring组件

@Service:用于标注业务层组件

@Controller:用于标注控制层组件(如struts中的action)

@Repository:用于标注数据访问的组件,DAO

@Component:泛指组件,不好归类的组件

这几个注解标注的JavaBean在使用时没有什么不同,但预计spring之后的版本会区分这几个注解的特殊性

建议在目前版本开发时按照此规则标注注解

如果不输入id,则默认当前类首字母小写

修改boy例子
@Component("boy")
public class Boy{
@Value(value="孙宇")
private String name;
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
}
Boy boy = ac.getBean("boy");
System.out.println(boy.getName());
组件bean赋值 @Autowired 自动装配
@Component(value="dog")
public class Dog{

}


@Component("boy")
public class Boy{
@Value(value="孙宇")
private String name;
//@Autowired
@Resource(name="dog")
private Dog dog;
public void setName(String name){
this.name = name;
}
public void setDog(Dog dog){
this.dog = dog;
}
public String getName(){
return name;
}
public Dog getDog(){
return dog;
}
}
Boy boy = ac.getBean("boy");
System.out.println(boy.getName());
System.out.println(boy.getDog().getName());
System.out.println(boy.getDog().getAge());
@Autowired和@Resource的区别

@Autowired和@Resource作用相当,@Autowired按byType的方式自动注入,@Resource按byName的方式自动注入

注解初始化方法和销毁方法配置

配置文件方式
<bean id="dog" class="com.icss.vo.Dog" scope="singleton"
init-method="initTest" destroy-method="destroyTest">
</bean>
注解方式
@PostConstruct
public void initTest(){
System.out.println("初始化方法");
}
@PreDestroy
public void destroyTest(){
System.out.println("销毁方法");
}
 配置文件注解
初始化方法 init-method @PostConstruct
销毁方法 destroy-method @PreDestroy
@Value注解
@Value(value="18")
private int age;
@Value(value="小李")
private String name;
@Value(value="5000.42")
private double salary;
<bean id="boy" class="com.icss.vo.Boy">
<property name="dog" ref="Dog"></property>
</bean>

@Resource注解

@Resource(name="dog")
private Dog dog;

使用service,dao,controller的注解实现MVC三层架构

@Repository("UserDAOImp1")
public class UserDAOImp1 implements IUserDAO{

}

@Service("UserServiceImp1")
public class UserServiceImp1 implements IUserService{
@Resource(name="UserDaoImp1")
IUserDAO iud;
public void deleteUser(){
//以往的实例化对象调用
//IUserDAO iud = new UserDAOImp1();
//iud.deleteUser();
iud.deleteUser();
}
}

public class TestController{
public static void main(String[] args){
new TestController().testContext();
}
public void testContext(){
//通常写法
//UserServiceImp1 u = new UserServiceImp1();
//项目开发中写法
//IUserService us = new UserServiceImp1();
//us.deleteUser();
//扫描 注解
String str = "com/icss/controller/applicationContext.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(str);
IUserService iud = (IUserService)ac.getBean("UserServiceImp1");
iud.deleteUser();
}
}
spring的十种注解
注解用处
@Component 用在vo类上的注解
@Controller 用在controller层上的注解
@Service 用在service层上的注解
@Repository 用在dao层的注解
@Value 用在setter注入基本数据类型的注解
@Resource 用在setter注入组件bean上的注解,通过name进行注入
@Autowired 用在setter注入组件bean上的注解,通过type进行注入
@PostConstruct 用在初始化方法上的注解
@PreDestroy 用在销毁方法上的注解
@Scope bean的作用域的注解
posted @ 2022-07-12 15:38  蓬岛er  阅读(83)  评论(0)    收藏  举报