Spring学习(四)

Spring Ioc容器

1、具有依赖注入功能的容器。负责实例化,定位,配置应用程序中的对象及建立这些对象间的依赖。在Spring中BeanFactory是Ioc容器的实际代表者。BeanFactory接口提供了IoC容器的基本功能。Spring Ioc容器通过读取配置文件中的配置元数据,通过元数据对应用中各个对象进行实例化及装配。

Spring Ioc容器管理的对象:Bean

1、定义

  • Bean就是由Spring容器初始化、装配及管理的对象,此外bean与应用程序中的其他对象没有什么区别.
  • Bean在容器内部由BeanDefinition对象表示。

2、BeanDefinition

  • 全限定类名(FQN):用于定义Bean的实现类;(必须的)
  • Bean行为定义:包括作用域(单例、原型创建)、是否惰性初始化及生命周期等;
  • Bean创建方式定义:说明是通过构造器还是工厂方法创建Bean;
  • Bean之间关系定义:即对其他bean的引用,也就是依赖关系定义,也就是依赖注入。

3、Bean的作用域

  • “singleton”(单例,通过单例缓存池实现)
  • “prototype”(原型,每次创建全新的bean)
  • 另外提供“request”、“session”、“global session”三种web作用域

Spring IoC容器创建Bean 的方式

1、根据Bean定义里的配置元数据使用反射机制来创建Bean。

  • 使用构造
  • 静态工程方法
  • 实例工厂方法
  • 使用 FactoryBean 方式

2、使用构造: 创建对象使用无参构造的方式,使用最多的一种方式,注入数据用setter 方法

Fox类

package ecut.ioc.creation;

public class Fox {
    
    private String id ;
    
    private String name ;
    
    public Fox() {
        super();
        System.out.println( "Fox 无参构造" );
    }
    
    public Fox(String id , String name) {
        super();
        this.id = id;
        this.name = name;
        System.out.println( "Fox( String , String ) 构造" );
    }
    
    @Override
    public String toString() {
        return "Fox [id=" + id + ", name=" + name + "]";
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

}

constructor-creation.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-4.3.xsd">

     <!-- 调用无参构造 -->
    <bean id="fox1" class="ecut.ioc.creation.Fox" >
        <property name="id" value="A001" />
        <property name="name" value="苏妲己" />
    </bean>
    <!-- 使用名称调用有参构造 ,建议使用可读性好-->
    <bean id="fox2" class="ecut.ioc.creation.Fox" >
        <constructor-arg name="id" value="B001" />
        <constructor-arg name="name" value="雪山飞狐" />
    </bean>
    <!-- 使用索引调用有参构造 -->
    <bean id="fox3" class="ecut.ioc.creation.Fox" >
        <constructor-arg index="0" value="B002" />
        <constructor-arg index="1" value="旋涡鸣人" />
    </bean>
</beans>

测试类

package ecut.ioc.creation;

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

public class BeanCreationByConstructor {

    public static void main(String[] args) {
        
        String configLocations = "classpath:ecut/**/constructor-creation.xml" ;
        
        AbstractApplicationContext container = new ClassPathXmlApplicationContext( configLocations );
        
        //需要有无参构造,不然会抛出BeanCreationException,因为没有指定默认的构造函数
        Fox fox1 = container.getBean( "fox1" ,  Fox.class );
        System.out.println( fox1 );
        
        Fox fox2 = container.getBean( "fox2" ,  Fox.class );
        System.out.println( fox2 );
        
        Fox fox3 = container.getBean( "fox3" ,  Fox.class );
        System.out.println( fox3 );
        
        container.close();
        
    }

}

3、静态工程方法:某个类里面有一个方法专门用创建这个类的对象

Sun类

package ecut.ioc.creation;

public class Sun {
    /*//"饿汉"式实现单例 
    private static final Sun SUN =new Sun();
    
    private Sun(){
        super();
        System.out.println( "构造方法执行" );
    }
    //调用getInstance()方法获取sun类型实例,调用类的静态方法是主动使用会导致 类被初始化
    public static Sun getInstance(){
        System.out.println( "使用静态方法返回 Sun 类型的实例" );
        //这个Sun 类型的实例是单例的
        return SUN ;
    }*/

    //懒汉式,线程安全实现单例 
    private static Sun SUN ;
    
    private Sun(){
        super();
        System.out.println( "构造方法执行" );
    }
    //调用getInstance()方法获取sun类型实例,调用类的静态方法是主动使用会导致 类被初始化
    public static Sun getInstance(){
        System.out.println( "使用静态方法返回 Sun 类型的实例" ); 
        //同步锁是类对应对象
        synchronized ( Sun.class ) {
            SUN = new Sun();
        }
        //这个Sun 类型的实例是单例的
        return SUN ;
    }

}

static-factory-method.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-4.3.xsd">

    <!-- factory-method指定的是静态方法,通过调用静态方法之前 -->
    <bean id="sun" 
             class="ecut.ioc.creation.Sun"  
             factory-method="getInstance" />
    
</beans>

测试类

package ecut.ioc.creation;

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

public class BeanCreationByStaticFactory {

    public static void main(String[] args) {
        
        String configLocations = "classpath:ecut/**/static-factory-method.xml" ;
        
        AbstractApplicationContext container = new ClassPathXmlApplicationContext( configLocations );
        
        System.out.println( "~~~~~~~~~~~~~~~~~" );
        //构造方法只执行一次,默认情况下,容器创建就已经创建了这个bean
        Sun s = container.getBean( "sun" ,  Sun.class );
        System.out.println( s );
        
        Sun x = container.getBean( "sun" ,  Sun.class );
        System.out.println( x );
        
        container.close();
        
    }

}

4、实例工厂方法:要有一个具体的工厂实例,有这个工厂实例去造bean

Car类

package ecut.ioc.creation;

public class Car {
    
    private String brand ; // 品牌
    
    public Car(){
        super();
        System.out.println( "Car无惨构造执行" );
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }
    
}

CarFactory类

package ecut.ioc.creation;

public class CarFactory {
    
    private String brandName ;
    
    public CarFactory() {
        super();
    }

    public CarFactory(String brandName) {
        super();
        this.brandName = brandName;
        System.out.println( "CarFactory( String ) 构造执行" );
    }

    public Car create(){
        System.out.println( "准备创建 Car 的实例" );
        Car c = new Car();
        c.setBrand( brandName );
        return c ;
    }

}

instance-factory-method.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-4.3.xsd">


    <!-- 先 创建 Car 工厂 -->
    <bean id="carFactory" class="ecut.ioc.creation.CarFactory" >
        <constructor-arg name="brandName" value="BYD" />
    </bean>
    
    <!-- 再 通过 工厂实例 ( carFactory ) 的 非静态方法来创建 Car -->
    <bean id="car" factory-bean="carFactory" factory-method="create" />
    
</beans>

测试类

package ecut.ioc.creation;

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

public class BeanCreationByInstanceFactory {

    public static void main(String[] args) {
        
        String configLocations = "classpath:ecut/**/instance-factory-method.xml" ;
        
        AbstractApplicationContext container = new ClassPathXmlApplicationContext( configLocations );
        
        System.out.println( "~~~~~~~~~~~~~~~~~" );
        
        Car c = container.getBean( "car" ,  Car.class );
        System.out.println( c.getBrand() );
        
        container.close();
        
    }

}

5、使用 FactoryBean 方式:FactoryBean 是一个接口,由FactoryBean类型的对象造另外一个对象

DateFactoryBean

package ecut.ioc.creation;

import java.util.Calendar;
import java.util.Date;

import org.springframework.beans.factory.FactoryBean;
//期望返回的类型xx,则xxFactoryBean implements FactoryBean<xx>
public class DateFactoryBean implements FactoryBean<Date>{
    
    private int year ;
    private int month ;
    private int date ;
    private int hour ;
    private int minute ;
    private int second ;
    
    private static final Calendar CALENDAR = Calendar.getInstance();
    
    public DateFactoryBean(){
        super();
        System.out.println( "DateFactoryBean()" );
    }

    @Override
    public Date getObject() throws Exception {
        System.out.println( "准备获取 Date 类型实例" );
        CALENDAR.set( year, month - 1 , date , hour , minute , second );
        Date date = CALENDAR.getTime();
        return date ;
    }

    @Override
    public Class<?> getObjectType() {
        return Date.class;
    }

    @Override
    public boolean isSingleton() {
        return false;
    }


    public int getYear() {
        return year;
    }

    public void setYear(int year) {
        this.year = year;
    }

    public int getMonth() {
        return month;
    }

    public void setMonth(int month) {
        this.month = month;
    }

    public int getDate() {
        return date;
    }

    public void setDate(int date) {
        this.date = date;
    }

    public int getHour() {
        return hour;
    }

    public void setHour(int hour) {
        this.hour = hour;
    }

    public int getMinute() {
        return minute;
    }

    public void setMinute(int minute) {
        this.minute = minute;
    }

    public int getSecond() {
        return second;
    }

    public void setSecond(int second) {
        this.second = second;
    }

    
}

约定:期望返回的类型xx,则xxFactoryBean implements FactoryBean<xx>

factory-bean-creation.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-4.3.xsd">

    <!-- 以前: 指定 class 是什么类型,就返回什么类型的实例 -->
    <bean id="d" class="java.util.Date" />
    
    <!-- 以前: 指定 class 是什么类型,就返回什么类型的实例,且是使用无参构造 创建bean,则必须要有无参构造-->
    <bean id="fox1" class="ecut.ioc.creation.Fox" >
        <property name="id" value="A001" />
        <property name="name" value="苏妲己" />
    </bean>
    
    <!-- 这里: 指定的 class 是 XxxFactoryBean ,但是返回的却不是  XxxFactoryBean 类型的实例 -->
    <!-- 而是返回了  XxxFactoryBean 内部的 getObject 方法所返回的那个实例 -->
    <bean id="birthdate" class="ecut.ioc.creation.DateFactoryBean" >
        <property name="year" value="1997" />
        <property name="month" value="7" />
        <property name="date" value="1" />
        <property name="hour" value="12" />
        <property name="minute" value="30" />
        <property name="second" value="18" />
    </bean>

</beans>

测试类

package ecut.ioc.creation;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

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

public class BeanCreationByFactoryBean {

    public static void main(String[] args) {
        
        String configLocations = "classpath:ecut/**/factory-bean-creation.xml" ;
        
        AbstractApplicationContext container = new ClassPathXmlApplicationContext( configLocations );
        
        Date d = container.getBean( "birthdate" ,  Date.class );
        System.out.println( d );
        
        DateFormat df = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" );
        
        System.out.println( df.format( d ) );
        
        container.close();
        
    }

}

转载请于明显处标明出处

https://www.cnblogs.com/AmyZheng/p/9249550.html

原文地址:https://www.cnblogs.com/AmyZheng/p/9249550.html