菜鸟学习第二十九天,IOC,以及Bean的了解

1.Spring最主要的2种设计模式
第二种:
1.IOC:(Inverse of Control)控制反转,DI(Dependency Injection)依赖注入,IOC和DI,这两个是一回事,只是名称不同,注意,这边的这个依赖包括很多东西,比如我们需要一个属性,这个属性就是依赖,Spring可以将这个依赖注入给我们,我们需要一个类,那么这个类就是依赖,Spring将这个依赖注入给我们。
1.1下面我们来讲IOC:
IOC:在java中比如A类要去获取B类的功能和属性,我们要在A类中获取B类的对象,那么我们需要在A类中new一个B类对象,然后控制B类对象实现我们需要的功能,这时候我们可以说A控制着B,而Spring-IOC则是将A类需要的由Spring-IOC获取然后将依赖注入到A类,如下图所示:
在这里插入图片描述
1.2那么IOC容器怎么去获取B类对象呢?
IOC容器可以调用无参构造或者有参构造来创建对象,我们先来看无参构造的方式:
首先,在Spring中,Bean代表Spring中的一个类的实例,这个实例可以是任何组件,也就是说Spring相当于一个工厂,Bean就是我们生产的产品,我们生产的产品是什么,取决于用户向我们要什么,通过配置文件中的bean标签将我们能生产的产品类(DemoB)关联起来,然后我们向客户(DemoA)注入我们根据客户所需要的产品类(DemoB).
要想获取bean就要先获取容器,用容器来装bean的实例:IOC中有2种容器
1.3 BeanFactory和ApplicationContext
ApplicationContext是BeanFactory的子接口,BeanFactory是比较低级的容器,而ApplicationContext是比较高级的容器,因为ApplicationContext还实现了其他接口,所以功能更强大。
这里BeanFactory是当客户端对象需要访问容器中的某个受管对象(也就是Spring控制的类)的时候,才对该受管对象进行初始化以及依赖注入操作。所以,相对来说,容器启动初期速度较快,所需要的资源有限。而ApplicationContext在BeanFactory的基础上构建,是相对比较高级的容器实现,除了拥有BeanFactory的所有支持,ApplicationContext还提供了其他高级特性,比如事件发布、国际化信息支持等,ApplicationContext所管理的对象,在该类型容器启动之后,默认全部初始化并绑定完成。所以,相对于BeanFactory来说,ApplicationContext要求更多的系统资源,同时,因为在启动时就完成所有初始化,容器启动时间较之BeanFactory也会长一些。
所以我们一般使用的是功能更强大的ApplicationContext,而不是底层的BeanFactory.
1.4 ApplicationContext接口包含了一个子接口ConfigurableApplicationContext
而ConfigurableApplicationContext包含了两个实现类:
1.ClassPathXmlApplicationContext:从类路径下加载配置文件
2.FileSystemXmlApplicationContext:从文件路径下加载配置文件
且子接口新增了两个主要方法:refresh()和close(),让ApplicationContext具有启动,刷新,关闭上下文这一系列功能。
ApplicationContext在初始化的时候就实例化了所有单例的bean,WebApplicationContext是专门为Web应用准备的,它允许从相对于web根目录的路径中完成初始化工作。
获取容器对象:

//这不就是多态吗
 ApplicationContext act=new ClassPathXmlApplicationContext("applicationContext.xml");

在这里插入图片描述
2.配置bean
配置bean有3种方式:通过全类名(反射),通过工厂方法(静态工厂方法和实例工厂方法),FactoryBean
2.1)第一种,通过全类名(反射)
在Spring配置文件(默认为ApplicationContext.xml)的Beans中添加一个Bean:

<bean id="demoB" class="com.qjw.test.DemoB">

</bean>

这里的id,是我们给这个bean取的一个唯一的标识,注意id不要重复,这里的class就是通过反射来获取到DemoB的Class对象(反射参考我上一天的学习记录),这样就在IOC容器中产生的DemoB类的一个bean实例,当我们想在别的类中使用的时候就可以通过先获取容器,然后调用容器的getBean(“bean的id”);方法拿到了,这里做个说明,getBean并不是ApplicationContext接口的方法,是父类BeanFactory接口的方法,如下:
我们先给出B类的代码:

public class DemoB {

    String name;
    int age;
    public DemoB()
    {

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

    public String getName() {
        return name;
    }
    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

}

首先要说的是:Spring中为我们提供了两种IOC容器用来存储实例:

然后在A类中:

public class DemoA {
    public static void main(String[] args) {
        //首先,通过new ClassPathXmlApplicationContext方式获取Spring配置文件,这样我们才能从IOC容器中获取里面的bean
        ApplicationContext act=new ClassPathXmlApplicationContext("applicationContext.xml");
        //然后调用getBean("bean的id"),根据bean的id来取出我们要的是哪个bean(也就是哪个类的bean实例)返回的是一个Object对象,我们要向下转型成我们实际的类型哦
        DemoB db=(DemoB)act.getBean("demoB");
        //现在就可以调用我们DemoB中的属性方法了
        db.setName("Spring");
        System.out.println(db.getName());

    }
}

结果:
在这里插入图片描述
值得注意的是getBean()不仅可以根据id来获取,还可以根据**“类”型**,等其他方法来获取,但是这个获取方法有弊端,**它要求我们的bean是唯一的,也就是我们在配置bean的时候如果配置了2个bean指向了同一个class(比如DemoB)**就会发生异常:

//这个类型的类是class,不是普通的数据类型哦,而且如果spring配置文件中有2个bean指向了DemoB就会发生异常要注意!!!
 DemoB db=(DemoB)act.getBean(DemoB.class);

2.2.1)通过工厂方法配置bean
DemoB类:

public class DemoB {
  
}
   

DemoC类:

public class DemoC {

    private static DemoB demoB=new DemoB();
    public static DemoB getInstance()
    {
        return demoB;
    }
}

Spring配置文件:

<bean id="demoB" class="com.qjw.test.DemoC" factory-method="getInstance">

DemoA类:

public class DemoA {
    public static void main(String[] args) {
        // 首先,通过new ClassPathXmlApplicationContext方式获取Spring配置文件,这样我们才能获取里面的bean
        ApplicationContext act=new ClassPathXmlApplicationContext("applicationContext.xml");
        //通过getBean获取实例
        DemoB db1=(DemoB) act.getBean("demoB");
        System.out.println(db1);
    }
}

打印结果:
在这里插入图片描述
可以看到,配置文件中class路径是DemoC,但是我们通过静态工厂方法直接创建了一个DemoB的bean
2.2.2 通过实例工厂方法配置bean
修改DemoC:

public class DemoC {

    private  DemoB demoB=new DemoB();
    public  DemoB getInstance()
    {
        return demoB;
    }
}

配置文件:

<bean id="demoB" class="com.qjw.test.DemoB">
    </bean>
    <bean id="demoB1" class="com.qjw.test.DemoC" factory-bean="demoB1" factory-method="getDemoB">
    </bean>

结果:
在这里插入图片描述
那么静态工厂和实例工厂的区别就在于:
静态工厂方法不需要先在配置文件中配置DemoB的bean实例就可以获取了,而实例工厂需要先实例DemoB后才能在DemoC中获取自己的实例,并且要指定factory-bean。
3.通过FactoryBean的方法。
首先新建一个类实现FactoryBean:

public class DemoB implements FactoryBean {
    @Override
    //返回bean的对象
    public Object getObject() throws Exception {
        return new DemoC();
    }

    @Override
    //返回bean的类型
    public Class<?> getObjectType() {
        return DemoC.class;
    }

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

然后配置文件:

<bean id="demoC" class="com.qjw.test.DemoB"></bean>

这里注意,我们要获取的bean是DemoC的bean,而我们class指向了我们实现了FactoryBean的类,id为我们要为DemoC指定的bean id,
通过FactoryBean配置返回的bean取决于FactoryBean实现类中 getObject()方法返回的实例

在这里插入图片描述
3.依赖注入的三种方式
1)属性注入
2)构造器注入
3)工厂注入(不推荐)

3.1属性注入(必须有一个默认的或者无参的构造函数,有setXXX();方法)
<property name="age" value="18"></property>
这就是bean的第一种依赖注入方法:属性注入,bean必须提供一个默认的构造函数,并且要注入值的类得为需要注入的属性提供set方法,因为实际上Spring是通过将属性标签中的name的值age转换为Age,然后变成setAge来为这个bean也就是我们的DemoB设置age属性的,所以这里property 中的age必须在DemoB中提供setAge的方法,不然会编译报错,而且除第一个字母可以忽略大小写(也就是大写也可以,小写也可以)以外,其他字符串都要大小写一致,这里的age对应DemoB类中的setAge().如下
在这里插入图片描述
这样才能为我们的属性设置值。

还有一种方法就是通过运行时类获取对象:

public class DemoA {
    public static void main(String[] args) {
        //首先,通过new ClassPathXmlApplicationContext方式获取Spring配置文件,这样我们才能获取里面的bean
        ApplicationContext act=new ClassPathXmlApplicationContext("applicationContext.xml");
        //通过运行时类获取对象
        DemoB db=act.getBean(DemoB.class);
        //通过bean id获取对象
         DemoB db=act.getBean("demoB");
        System.out.println("name="+db.name+"\n"+"age="+db.age);
    }
}

结果:
在这里插入图片描述
在这里插入图片描述
3.2构造器注入:
多个构造器配置多个bean,可以添加type属性来区分
首先为DemoB添加有参构造函数:

public class DemoB {

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

    }
    
}

然后是配置文件中的bean:

 <bean id="demoB" class="com.qjw.test.DemoB">
       //constructor-arg 就是构造函数的参数,name要和构造函数传递的参数一样,constructor-arg上下位置无所谓
       <constructor-arg name="name" value="Hi Spring"></constructor-arg>
        <constructor-arg name="age" value="20"></constructor-arg>
    </bean>

也可以通过index来指定参数:

    <bean id="demoB" class="com.qjw.test.DemoB">
        //index="0",代表第一个参数,以此类推
        <constructor-arg index="0" value="Hi Spring"></constructor-arg>
        <constructor-arg index="1" value="20"></constructor-arg>
    </bean>

然后是DemoA:
获取对象的方式和无参构造函数一致

public class DemoA {
    public static void main(String[] args) {
        //首先,通过new ClassPathXmlApplicationContext方式获取Spring配置文件,这样我们才能获取里面的bean
        ApplicationContext act=new ClassPathXmlApplicationContext("applicationContext.xml");
        //通过getBean id来创建实例
        DemoB db=(DemoB) act.getBean("demoB");
        System.out.println("name="+db.name+"\n"+"age="+db.age);




    }
}

结果:
在这里插入图片描述
字面值的定义:
在这里插入图片描述
在这里插入图片描述
4.Bean之间的引用
4.1 通过ref=“bean的id”指定依赖的bean,如果是DemoB需要DemoC的依赖,同样和属性一样应该将DemoC和引用设置为成员变量,然后提供setxxx();方法,注入依赖。
比如:
首先是DemoC:

public class DemoC {
    String sex;
    String work;
    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getWork() {
        return work;
    }

    public void setWork(String work) {
        this.work = work;
    }
    
}

因为DemoB关联DemoC,所以我们在DemoB定义一个DemoC的成员变量,然后提供setxxx()方法:(还是那个点,setxxx方法要和DemoC的bean id一致)

public class DemoB {

    String name;
    int age;
    DemoC demoC;

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public DemoC getDemoC() {
        return demoC;
    }

    public void setDemoC(DemoC demoC) {
        this.demoC = demoC;
    }
}

然后再配置文件中:


    <bean id="demoB" class="com.qjw.test.DemoB">
       <property name="name" value="Spring"></property>
        <property name="age" value="15"></property>
        //指定name为DemoB中的setDemoC()方法的转换demoC,指定ref为DemoC的bean id
        <property name="demoC" ref="demoC"></property>
    </bean>
    <bean id="demoC" class="com.qjw.test.DemoC">
        <property name="sex" value="女"></property>
        <property name="work" value="程序猿"></property>
    </bean>

这样就将C的依赖注入到了B,我们再来实现A:

public class DemoA {
    public static void main(String[] args) {
        //首先,通过new ClassPathXmlApplicationContext方式获取Spring配置文件,这样我们才能获取里面的bean
        ApplicationContext act=new ClassPathXmlApplicationContext("applicationContext.xml");
        //通过getBean id来创建实例
        DemoB db=(DemoB) act.getBean("demoB");
        System.out.println("name="+db.name+"\n"+"age="+db.age+"\n"+"sex="+db.demoC.sex+"\n"+"work="+db.demoC.work);




    }
}

在这里插入图片描述
如果DemoC有个集合属性:
首先DemoC:

public class DemoC {
    String sex;
    String work;
    List<String> list;
    public List<String> getList() {
        return list;
    }

    public void setList(List<String> list) {
        this.list = list;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getWork() {
        return work;
    }

    public void setWork(String work) {
        this.work = work;
    }

}

然后配置文件:

<bean id="demoB" class="com.qjw.test.DemoB">
       <property name="name" value="Spring"></property>
        <property name="age" value="15"></property>
        <property name="demoC" ref="demoC"></property>
    </bean>

    <bean id="demoC" class="com.qjw.test.DemoC">
        <property name="sex" value="女"></property>
        <property name="work" value="程序猿"></property>
        //指定name为setXXX()的转换list,然后为集合设置value
        <property name="list">
            <list>
                <value>第一</value>
                <value>第二</value>
            </list>
        </property>
    </bean>

DemoB不做修改:

public class DemoB {

    String name;
    int age;
    DemoC demoC;
    public DemoC getDemoC() {
        return demoC;
    }

    public void setDemoC(DemoC demoC) {
        this.demoC = demoC;
    }
    
    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }


}

然后是DemoA:

public class DemoA {
    public static void main(String[] args) {
        //首先,通过new ClassPathXmlApplicationContext方式获取Spring配置文件,这样我们才能获取里面的bean
        ApplicationContext act=new ClassPathXmlApplicationContext("applicationContext.xml");
        //通过getBean id来创建实例
        DemoB db=(DemoB) act.getBean("demoB");
        System.out.println("name="+db.name+"\n"+"age="+db.age+"\n"+"sex="+db.demoC.sex+"\n"+"work="+db.demoC.work);
        System.out.println(db.demoC.list);
    }
}

4.2 内部bean
内部bean只能为内部所用,外部不可以被外部引用,所以不用定义id,用一个属性标签包裹,name为DemoB定义的成员变量:DemoC demoC;
DemoB需要DemoC的依赖,那么:

<bean id="demoB" class="com.qjw.test.DemoB">
        <property name="demoC">
            <bean class="com.qjw.test.DemoC">
                <constructor-arg value="15"></constructor-arg>
            </bean>
        </property>

    </bean>

4.3 给属性赋值为null
null的专属标记:<null/>

<constructor-arg ><null/></constructor-arg>

4.4 配置集合bean
将集合配置成一个bean,需要导入util声明,拥有bean的所有定义

<util:list id="list1">
        <value>12</value>
        <value>sp</value>
        <ref bean="demoB"></ref>
    </util:list>

如上,有id供别的bean使用,也可以依赖别的bean(demoB),可以添加value
4.5使用p命名空间
需要先导入p命名空间

<bean id="demoB" class="com.qjw.test.DemoB" p:name="spring" p:democ1-ref="demoC">
 </bean>

如图,可以给属性配置value,可以配置依赖

在这里插入图片描述
5.bean的自动装配
下面介绍bean的
自动装载(配)autowire和依赖检查dependency-check属性(已过时移除):
首先说明为什么要使用这个属性:
当我们要往一个bean里注入另外一个bean的依赖,我们会使用<property> + <ref/>标签的形式。但是对于大型项目,假设有一个DemoB被多个bean引用注入,如果DemoB的id因为某种原因修改了,那么所有引用了DemoB的bean的<ref/>标签内容都得修改,这时候如果使用autowire="",那么引用了DemoB的bean就完全不用修改了。所以说自动装载(配)是为了将依赖注入“自动化”的一个简化配置的操作。尽管后来Spring为我们提供了注解自动装配,但是我们依旧先用这种方式来了解用法,才能更好理解这些概念。
自动装载:autowire=
no
(默认)不采用autowire机制.。这种情况,当我们需要使用依赖注入,只能用标签。
byName
通过属性的名称自动装配(注入)。Spring会在容器中查找名称与bean属性名称一致的bean,并自动注入到bean属性中。当然bean的属性需要有setter方法。例如:bean A有个属性master,master的setter方法就是setMaster,A设置了autowire=“byName”,那么Spring就会在容器中查找名为master的bean通过setMaster方法注入到A中。
byType
通过类型自动装配(注入)。Spring会在容器中查找类(Class)与bean属性类一致的bean,并自动注入到bean属性中,如果容器中包含多个这个类型的bean,Spring将抛出异常。如果没有找到这个类型的bean,那么注入动作将不会执行。
constructor
比如DemoB依赖DemoD,那么在DemoB的bean中添加autowire=“constructor“ 然后在B的构造函数的参数中指定一个参数为(DemoD demoD),那么自动装载就根据这个参数所属的类型也就是DemoD,去bean中寻找class属性除去包名是DemoD的类,将这个类所属的bean自动装载到DemoB中,类似于byType,如果有多个属于DemoD的bean,那么会报错,不同于byType,如果没有找到,也会报错,
default
采用父级标签(即beans的default-autowire属性)的配置。
依赖检查:dependency-check=
simple:对基本类型,字符型和集合进行依赖检查,如果没有设置抛出UnsatisfiedDependencyException
object:对依赖的对象进行检查,如果没有设置抛出UnsatisfiedDependencyException
none:不进行依赖检查(默认模式)
all:对全部属性进行检查(这个也可以使用在beans就是管理bean的那个标签中使用方式是default-dependency-check=“all”,但是会被bean自己的依赖检查覆盖如果有的话)
依赖检查一般和自动装载进行配套使用。如果没有自动装载,也就没有依赖检查的必要了。
下面我们来演示自动装载:
演示到这里,发现一个不忍直视的事实,那就是,为什么别人直接System.out.println(db1);就行了,而我还要对象.属性输出,原来是有个我没注意的的toString方法,也就是说如果重写toString方法,调用对象的时候,会自动调用对象的toString方法,后面的示例都会添加上toString,注意。
**下面来演示自动装载的autowire=“byName”:**包含的类有DemoA,DemoB,DemoC,DemoD,其中DemoB设置自动装载
配置文件:


    <bean id="demoB" class="com.qjw.test.DemoB" autowire="byName">
    <property name="name" value="Spring1"></property>
    <property name="age" value="15"></property>
    </bean>

    <bean id="demoC2" class="com.qjw.test.DemoC">
        <property name="Sex" value="女"></property>
        <property name="work" value="程序猿"></property>
        <property name="name" value="Spring2"></property>
        <property name="list">
            <list>
                <value>第一</value>
                <value>第二</value>
            </list>
        </property>
    </bean>
    <bean id="demoD" class="com.qjw.test.DemoD">
        <property name="namesage" value="Spring4"></property>
    </bean>

然后是DemoB:

public class DemoB {

    String name;
    int age;
    DemoC demoC1;//我特意取的不一样的标识
    DemoD demoD1;//我特意取的不一样的标识
    public DemoB()
    {

    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public DemoC getDemoC2() {
        return demoC1;
    }

    public void setDemoC2(DemoC demoC3) {//也就是说set方法setDemoC2和DemoC的对象引用demoC1和传入对象参数demoC3三个不一样,这边要注意的是bean中的id
        this.demoC1 = demoC3;
    }

    public DemoD getDemoD() {
        return demoD1;
    }

    public void setDemoD(DemoD demoD) {
        this.demoD1 = demoD;
    }

    @Override
    public String toString() {
        return "DemoB{" +
                "name='" + name + '\'' +
                ", age=" + age +
                "\n demoC=" + demoC1 +
                "\n demoD=" + demoD1 +
                '}';
    }
}

DemoC:

public class DemoC {
    String sex;
    String work;
    String name;
    int age;
    List<String> list;

    public DemoC()
    {

    }
    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public List<String> getList() {
        return list;
    }

    public void setList(List<String> list) {
        this.list = list;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getWork() {
        return work;
    }

    public void setWork(String work) {
        this.work = work;
    }

    public String toString() {
        return "DemoC{" +
                "sex='" + sex + '\'' +
                ", work='" + work + '\'' +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", list=" + list +
                '}';
    }}


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

DemoD:

public class DemoD {
    String namesage;

    public String getNamesage() {
        return namesage;
    }

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

    @Override
    public String toString() {
        return "DemoD{" +
                "name='" + namesage + '\'' +
                '}';
    }
}

DemoA:

public class DemoA {
    public static void main(String[] args) {
        // 首先,通过new ClassPathXmlApplicationContext方式获取Spring配置文件,这样我们才能获取里面的bean
        ApplicationContext act=new ClassPathXmlApplicationContext("applicationContext.xml");
        //通过getBean id来创建实例
        DemoB db1=(DemoB) act.getBean("demoB");
        System.out.println(db1);




    }
}

结果:
在这里插入图片描述
从这个例子可以看出autowire=“byName”,根据的是设置autowire属性的bean也就是DemoB所需要注入依赖类的setXXX()方法(这里是setDemoC2()和setDemoD())和对应bean的id(这里是demoC2和demoD分别为DemoC和DemoD类的bean id)比较进行自动依赖注入的。
我设置不同的引用名是为了测试其他名字对byname的影响,实验证明如上所示,如果bean id和setxxx()除第一个字母外其他不相同,则不能注入依赖。
注入依赖之后因为获取到了该类的实例,就可以使用该类的所有属性和方法了,就像DemoC一样,虽然DemoB属性里面并没有list,但注入依赖后就可以使用了。
在这里插入图片描述
下面来演示自动装载的autowire=“byType”:

<bean id="demoC2" class="com.qjw.test.DemoC">
        <property name="Sex" value="女"></property>
        <property name="work" value="程序猿"></property>
        <property name="name" value="Spring2"></property>
        <property name="list">
            <list>
                <value>第一</value>
                <value>第二</value>
            </list>
        </property>
    </bean>
    <bean id="demoD" class="com.qjw.test.DemoD">
        <property name="namesage" value="Spring4"></property>
    </bean>
    <bean id="demoD2" class="com.qjw.test.DemoD">
        <property name="namesage" value="Spring4"></property>
    </bean>

如果有2个bean指向DemoD类,那么就是说有2个DemoD实例,那么我们通过byType就会报错,原因就是因为byType是根据是什么类型(比如demoC2 bean是DemoC类型的实例)也就是在DemoB中的成员变量**DemoC demoC1;**用这个DemoC和配置文件中bean的class比较class="com.qjw.test.DemoC",除去包名,如果一样那么就注入DemoC的依赖。
在这里插入图片描述
然后是autowire=“constructor”:
修改DemoB:

public class DemoB {

    String name;
    int age;
    DemoC demoC1;
    DemoD demoD1;
    public DemoB(DemoD demoD1)//这个DemoB和上面的例子多了个构造函数
    {
        this.demoD1=demoD1;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public DemoC getDemoC2() {
        return demoC1;
    }

    public void setDemoC2(DemoC demoC3) {
        this.demoC1 = demoC3;
    }

    public DemoD getDemoD() {
        return demoD1;
    }

    public void setDemoD(DemoD demoD) {
        this.demoD1 = demoD;
    }

    @Override
    public String toString() {
        return "DemoB{" +
                "name='" + name + '\'' +
                ", age=" + age +
                "\n demoC=" + demoC1 +
                "\n demoD=" + demoD1 +
                '}';
    }
}

这个的意思就是只要这个构造函数中的DemoD类型,和容器中属性class为class="com.qjw.test.DemoD"的bean,除去包名就是DemoD,这两个一样,那么就注入这个bean的依赖

public DemoB(DemoD demoD1)//这个DemoB和上面的例子多了个构造函数
    {
        this.demoD1=demoD1;
    }

结果:
在这里插入图片描述
这里demoC为null,说明没有注入demoC的依赖,因为我们没有在DemoB的构造函数中,将要匹配的类作为参数传递进去,如果要注入DemoC的依赖,我们修改DemoB的构造函数:

  public DemoB(DemoD demoD1,DemoC demoC)
    {
        this.demoD1=demoD1;
        this.demoC1=demoC;

    }

结果:
在这里插入图片描述
5)因为依赖检查被移除,这里我们就不再示例了,我们要了解的是依赖检查是用来检查bean的属性是否符合依赖检查设定的类型的,后续的Spring都提倡实现零bean配置,因为大量的bean配置对于维护也是很头疼的事情,明天将学习新的方式
在这里插入图片描述
6.bean的作用域
1)bean的作用域scope属性,也是bean的属性之一,默认值是singleton:
singleton,单例,只会创建一个实例
prototype,表示每次从容器取出bean时也就是getBean()的时候,都会生成一个新实例
request,该属性是基于web的表示每次接受一个请求时,都会生成一个新实例,在这种情况下,request与prototype一样
session,表示在每个session中该实例只有一个
glovalSession,
通常使用前两种,request和session在web项目中使用,最后一个在某些场景使用就先不关心它了。
singleton:
首先我们创建DemoB:

public class DemoB {

    String name;
    int age;
   
    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }


}

然后我们为其配置bean:(这里2个bean都指向同一个DemoB)

 <bean id="demoB" class="com.qjw.test.DemoB">
    <property name="name" value="Spring1"></property>
    <property name="age" value="15"></property>
    </bean>

然后是DemoA:

public class DemoA {
    public static void main(String[] args) {
        //首先,通过new ClassPathXmlApplicationContext方式获取Spring配置文件,这样我们才能获取里面的bean
        ApplicationContext act=new ClassPathXmlApplicationContext("applicationContext.xml");
        //通过
        DemoB db1=(DemoB) act.getBean("demoB");
        DemoB db2= (DemoB) act.getBean("demoB");
       System.out.println("db1:"+"name="+db1.name+" "+"age="+db1.age);
        System.out.println("db2:"+"name="+db2.name+" "+"age="+db2.age);
        System.out.println("db1==db2?"+" "+"答案是:"+db1.equals(db2));
    }
}

结果:
在这里插入图片描述
所以可以得出结论在Spring创建bean时设置scope=singleton只会创建一个实例
prototype:
接下来我们修改bean:将scope改为prototype

 <bean id="demoB" class="com.qjw.test.DemoB" scope="prototype">
    <property name="name" value="Spring1"></property>
    <property name="age" value="15"></property>
    </bean>

结果:
在这里插入图片描述
其他2个就不演示了,现在我们了解了bean的作用域
在这里插入图片描述
2)下面我们说说bean的继承
bean中的继承和java类似,可以继承上父类bean的属性,继承。。。额你想说方法是把,答案是,这没意义啊,这子父bean就是同一个类的对象啊,也就是说子父bean对象的方法是一样的,不用继承,就不用多此一举了,接下来演示bean的继承:
修改配置文件:bean之间继承用parent=“父类bean id”来实现

<bean id="demoB1" class="com.qjw.test.DemoB">
    <property name="name" value="Spring1"></property>
    <property name="age" value="15"></property>
    </bean>
    <bean id="demoB2" class="com.qjw.test.DemoB" parent="demoB1">
        
    </bean>

DemoA:

public class DemoA {
    public static void main(String[] args) {
        //首先,通过new ClassPathXmlApplicationContext方式获取Spring配置文件,这样我们才能获取里面的bean
        ApplicationContext act=new ClassPathXmlApplicationContext("applicationContext.xml");
        //通过getBean id来创建实例
        DemoB db1=(DemoB) act.getBean("demoB1");
        DemoB db2= (DemoB) act.getBean("demoB2");
        System.out.println("db1:"+"name="+db1.name+" "+"age="+db1.age);
        System.out.println("db2:"+"name="+db2.name+" "+"age="+db2.age);

        System.out.println("db1==db2?"+" "+"答案是:"+db1.equals(db2));
    }
}

结果:
在这里插入图片描述
注意点:这里我们默认scope为singleton,只会创建一个实例是对于一个bean的,所以你再配置一个bean然后指向这个类,那么就会再新建一个唯一的实例bean哦,而且如上例所示,如果demoB2配置了自己的prototype,那么会覆盖父类的:

<bean id="demoB1" class="com.qjw.test.DemoB" >
    <property name="name" value="Spring1"></property>
    <property name="age" value="15"></property>
    </bean>
    <bean id="demoB2" class="com.qjw.test.DemoB" parent="demoB1">
        <property name="name" value="Spring2"></property>
        <property name="age" value="19"></property>
    </bean>

结果:
在这里插入图片描述
上面是在同类中进行的bean继承,那么在不同类进行继承会怎么样呢?
答案是不可以,除非两个类有相同的属性,但是这样又没有意义,否则会报错。而且,子类的bean可以不用填class属性的,因为都是说在同一个类继承的.
在这里插入图片描述
7.然后是不同类Bean之间的依赖,继承讲的是同一个类,而bean之间的依赖讲的是不同的类,这边划重点,depends-on=“bean id”
配置了depends-on的bean会在被指定的bean初始化之后初始化,销毁前销毁,也就是DemoB的bean对象的创建依赖于DemoC的bean对象创建,比如:
这是配置文件:

<bean id="demoB1" class="com.qjw.test.DemoB" depends-on="demoC">
    <property name="name" value="Spring1"></property>
    <property name="age" value="15"></property>
    </bean>
    <bean id="demoC" class="com.qjw.test.DemoC">
        <property name="sex" value="女"></property>
        <property name="work" value="程序猿"></property>
        <property name="list">
            <list>
                <value>第一</value>
                <value>第二</value>
            </list>
        </property>
    </bean>

然后我们在DemoB和DemoB构造函数上各加上:

public DemoB()
    {
        System.out.println("DemoB");
    }
 public DemoC()
    {
        System.out.println("DemoC");
    }

然后是DemoA:

public class DemoA {
    public static void main(String[] args) {
        //首先,通过new ClassPathXmlApplicationContext方式获取Spring配置文件,这样我们才能获取里面的bean
        ApplicationContext act=new ClassPathXmlApplicationContext("applicationContext.xml");
        //通过getBean id来创建实例
        DemoB db1=(DemoB) act.getBean("demoB1");
        DemoC db2= (DemoC) act.getBean("demoC");

    }
}

可以看到按照程序流程DemoB先实例化,但是结果:
在这里插入图片描述
是因为DemoB依赖于DemoC,所以先实例化DemoC,而在上面的继承中,实例化的先后顺序是根据你创建Bean的先后顺序来执行的,和配置文件中bean标签的上下顺序无关
在这里插入图片描述

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值