spring6之容器:IOC

 容器:IOC

控制反转(Ioc)

                                                                

IoC容器在Spring的实现

Spring 的 IoC 容器就是 IoC思想的一个落地的产品实现。IoC容器中管理的组件也叫做 bean。在创建 bean 之前,首先需要创建IoC 容器。Spring 提供了IoC 容器的两种实现方式:

**①BeanFactory**

这是 IoC 容器的基本实现,是 Spring 内部使用的接口。面向 Spring 本身,不提供给开发人员使用。

**②ApplicationContext**

BeanFactory 的子接口,提供了更多高级特性。面向 Spring 的使用者,几乎所有场合都使用 ApplicationContext 而不是底层的 BeanFactory。

**③ApplicationContext的主要实现类**

获取bean的三种方式:

package com.zzq.spring6.iocxml;

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

public class TestUser {
    public static void main(String[] args) {
        ApplicationContext context=new
                ClassPathXmlApplicationContext("bean.xml");
        //根据id获取bean
        User user1=(User) context.getBean("user1");
        System.out.println(""+user1);
        //根据类型获取bean
        User user2=context.getBean(User.class);
        System.out.println(""+user2);
        //根据id和类型获取bean
        User user3=context.getBean("user",User.class);
        System.out.println(""+user3);
    }
}

如果组件类实现了接口,根据接口类型可以获取 bean 吗?

> 可以,前提是bean唯一

如果一个接口有多个实现类,这些实现类都配置了 bean,根据接口类型可以获取 bean 吗?

> 不行,因为bean不唯一
依赖注入:

1、类有属性,创建对象过程中,向属性设置值

第一种方式:基于set方法完成

package com.zzq.spring6.iocxml.di;

import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestBook {
    @Test
    public void testSetter(){
        ApplicationContext context=new
                ClassPathXmlApplicationContext("bean-di.xml");
        Book book = context.getBean("book", Book.class);
        System.out.println(book);
    }
}

 book.java

package com.zzq.spring6.iocxml.di;

public class Book {
    private String bname;
    private  String author;

    @Override
    public String toString() {
        return "Book{" +
                "bname='" + bname + '\'' +
                ", author='" + author + '\'' +
                '}';
    }

    public String getBname() {
        return bname;
    }

    public void setBname(String bname) {
        this.bname = bname;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public Book(String bname, String author) {
        this.bname = bname;
        this.author = author;
    }

    public Book() {
    }
}

bean-di.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="book" class="com.zzq.spring6.iocxml.di.Book">
    <property name="author" value="后端"></property>
    <property name="bname" value="java"></property>
</bean>
</beans>

第二种方式:基于构造器完成

<?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">
<!--1、set方法注入-->
    <bean id="book" class="com.zzq.spring6.iocxml.di.Book">
        <property name="author" value="后端"></property>
        <property name="bname" value="java"></property>
    </bean>
    <!--    2、构造器注入-->
    <bean id="bookCon" class="com.zzq.spring6.iocxml.di.Book">
        <constructor-arg name="author" value="java开发"></constructor-arg>
        <constructor-arg name="bname" value="spring"></constructor-arg>
    </bean>
</beans>
package com.zzq.spring6.iocxml.di;

import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestBook {
  
    @Test
    public void testConstructor(){
        ApplicationContext context=new
                ClassPathXmlApplicationContext("bean-di.xml");
        Book book = context.getBean("bookCon", Book.class);
        System.out.println(book);
    }
}

特殊值处理

##### ①字面量赋值

> 什么是字面量?
>
> int a = 10;
>
> 声明一个变量a,初始化为10,此时a就不代表字母a了,而是作为一个变量的名字。当我们引用a的时候,我们实际上拿到的值是10。
>
> 而如果a是带引号的:'a',那么它现在不是一个变量,它就是代表a这个字母本身,这就是字面量。所以字面量没有引申含义,就是我们看到的这个数据本身。

```xml
<!-- 使用value属性给bean的属性赋值时,Spring会把value属性的值看做字面量 -->
<property name="name" value="张三"/>
```

##### ②null值

```xml
<property name="name">
    <null />
</property>
```

> 注意:
>
> ```xml
> <property name="name" value="null"></property>
> ```
>
> 以上写法,为name所赋的值是字符串null

##### ③xml实体

```xml
<!-- 小于号在XML文档中用来定义标签的开始,不能随便使用 -->
<!-- 解决方案一:使用XML实体来代替 -->
<property name="expression" value="a &lt; b"/>
```

##### ④CDATA节

```xml
<property name="expression">
    <!-- 解决方案二:使用CDATA节 -->
    <!-- CDATA中的C代表Character,是文本、字符的含义,CDATA就表示纯文本数据 -->
    <!-- XML解析器看到CDATA节就知道这里是纯文本,就不会当作XML标签或属性来解析 -->
    <!-- 所以CDATA节中写什么符号都随意 -->
    <value><![CDATA[a < b]]></value>
</property>
```


为对象类型属性赋值:

第一种方式:

引入外部bean

1、创建两个类对象:dept和emp

2、在emp的bean标签里面,使用property引入dept的bean

package com.zzq.spring6.iocxml.ditest;
//部门类
public class Dept {

    private  String dname;

    public void setDname(String dname) {
        this.dname = dname;
    }

    public  void info(){
        System.out.println("部门名称:"+dname);
    }
}
package com.zzq.spring6.iocxml.ditest;
//员工类
public class Emp {
    //对象类型属性:员工属于某个部门
    private Dept dept;
    private  String ename;
    private Integer age;

    public Dept getDept() {
        return dept;
    }
    public  void  work(){
        System.out.println(ename+"emp work...."+age);
        dept.info();
    }
    public void setDept(Dept dept) {
        this.dept = dept;
    }

    public String getEname() {
        return ename;
    }

    public void setEname(String ename) {
        this.ename = ename;
    }

    public Integer getAge() {
        return age;
    }

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


}
package com.zzq.spring6.iocxml.ditest;

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

public class TestEmp {
    public static void main(String[] args) {


    ApplicationContext context=new
            ClassPathXmlApplicationContext("bean-ditest.xml");
        Emp emp = context.getBean("emp", Emp.class);
        emp.work();
    }
}
<?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="dept" class="com.zzq.spring6.iocxml.ditest.Dept">
        <property name="dname" value="维和部"></property>
    </bean>
    <bean id="emp" class="com.zzq.spring6.iocxml.ditest.Emp">
        <!--普通属性注入-->
        <property name="age" value="23"></property>
        <property name="ename" value="aa"></property>
<!--        注入对象类型属性-->
        <property name="dept" ref="dept"></property>
    </bean>
</beans>

第二种方式:

内部bean的注入

<!--    内部bean注入-->
    <bean id="emp2" class="com.zzq.spring6.iocxml.ditest.Emp">
        <!--普通属性注入-->
        <property name="age" value="2344"></property>
        <property name="ename" value="aabbb"></property>
        <!--        注入对象类型属性-->
        <property name="dept" >
            <bean id="dept2" class="com.zzq.spring6.iocxml.ditest.Dept">
                <property name="dname" value="维和部111"></property>
            </bean>
        </property>
    </bean>

 第三种方式:

级联赋值

<!--    第三种方式  级联赋值-->
    <bean id="dept3" class="com.zzq.spring6.iocxml.ditest.Dept">
        <property name="dname" value="技术研发部"></property>
    </bean>
    <bean id="emp3" class="com.zzq.spring6.iocxml.ditest.Emp">
        <property name="ename" value="Tom"></property>
        <property name="age" value="22"></property>
        <property name="dept" ref="dept3"></property>
        <property name="dept.dname" value="测试部"></property>
    </bean>

注入数组类型的属性 

package com.zzq.spring6.iocxml.ditest;

import java.lang.reflect.Array;
import java.util.Arrays;

//员工类
public class Emp {
    //对象类型属性:员工属于某个部门
    private Dept dept;
    private String ename;
    private Integer age;
    private String[] loves;

    public void work() {
        System.out.println(ename + "emp work...." + age);
        dept.info();
        System.out.println(Arrays.toString(loves));
    }
    public void setLoves(String[] loves) {
        this.loves = loves;
    }

    public Dept getDept() {
        return dept;
    }
    public void setDept(Dept dept) {
        this.dept = dept;
    }

    public String getEname() {
        return ename;
    }

    public void setEname(String ename) {
        this.ename = ename;
    }

    public Integer getAge() {
        return age;
    }

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


}
<?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="dept" class="com.zzq.spring6.iocxml.ditest.Dept">
        <property name="dname" value="维和部"></property>
    </bean>
    <bean id="emp" class="com.zzq.spring6.iocxml.ditest.Emp">
        <!--普通属性注入-->
        <property name="age" value="23"></property>
        <property name="ename" value="aa"></property>
        <!--        注入对象类型属性-->
        <property name="dept" ref="dept"></property>
<!--        数组类型属性-->
        <property name="loves">
            <array>
                <value>睡觉</value>
                <value>听歌</value>
                <value>追剧</value>
            </array>
        </property>
    </bean>
</beans>

为集合类型属性赋值

List集合属性的注入

<?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="empone" class="com.zzq.spring6.iocxml.ditest.Emp">
    <!--普通属性注入-->
    <property name="age" value="23"></property>
    <property name="ename" value="aa"></property>
    </bean>
    <bean id="emptwo" class="com.zzq.spring6.iocxml.ditest.Emp">
        <!--普通属性注入-->
        <property name="age" value="33"></property>
        <property name="ename" value="agga"></property>
    </bean>
<bean id="dept" class="com.zzq.spring6.iocxml.ditest.Dept">
    <property name="dname" value="技术部"></property>
    <property name="empList">
        <list>
            <ref bean="empone"></ref>
            <ref bean="emptwo"></ref>
        </list>
    </property>
</bean>


</beans>
package com.zzq.spring6.iocxml.ditest;

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

public class TestDept {
    public static void main(String[] args) {


    ApplicationContext context=new
            ClassPathXmlApplicationContext("bean-dilist.xml");
       Dept dept = context.getBean("dept", Dept.class);
        dept.info();
    }
}
package com.zzq.spring6.iocxml.ditest;

import java.util.List;

//部门类
public class Dept {
//一个部门有很多员工
    private List<Emp> empList;

    public List<Emp> getEmpList() {
        return empList;
    }

    public void setEmpList(List<Emp> empList) {
        this.empList = empList;
    }

    public String getDname() {
        return dname;
    }

    private  String dname;

    public void setDname(String dname) {
        this.dname = dname;
    }

    public  void info(){
        System.out.println("部门名称:"+dname);
        for (Emp emp:empList) {
            System.out.println(emp.getEname());
        }
    }
}

map集合属性的注入

Student类

package com.zzq.spring6.iocxml.dimap;

import java.util.Map;

public class Student {
    private String sid;
    private String name;
    private Map<String, Teacher> teacherMap;

    public void run() {
        System.out.println("学生编号: " + sid +
                "学生名称: " + name);
        System.out.println(teacherMap);
    }

    @Override
    public String toString() {
        return "Student{" +
                "sid='" + sid + '\'' +
                ", name='" + name + '\'' +
                ", teacherMap=" + teacherMap +
                '}';
    }

    public Map<String, Teacher> getTeacherMap() {
        return teacherMap;
    }

    public void setTeacherMap(Map<String, Teacher> teacherMap) {
        this.teacherMap = teacherMap;
    }

    public String getSid() {
        return sid;
    }

    public void setSid(String sid) {
        this.sid = sid;
    }

    public String getName() {
        return name;
    }

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

Teacher类

package com.zzq.spring6.iocxml.dimap;

public class Teacher {
    private String teacherId;
    private String teacherName;

    @Override
    public String toString() {
        return "Teacher{" +
                "teacherId='" + teacherId + '\'' +
                ", teacherName='" + teacherName + '\'' +
                '}';
    }

    public String getTeacherId() {
        return teacherId;
    }

    public void setTeacherId(String teacherId) {
        this.teacherId = teacherId;
    }

    public String getTeacherName() {
        return teacherName;
    }

    public void setTeacherName(String teacherName) {
        this.teacherName = teacherName;
    }
}

package com.zzq.spring6.iocxml.dimap;

import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestStu {
    @Test
    public void testStu(){
        ApplicationContext context=new
                ClassPathXmlApplicationContext("bean-dimap.xml");
        Student student = context.getBean("student", Student.class);
        student.run();
    }
}
<?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="student" class="com.zzq.spring6.iocxml.dimap.Student">
    <property name="name" value="aa"></property>
    <property name="sid" value="111"></property>
    <property name="teacherMap">
        <map>
            <entry>
                <key>
                    <value>10001</value>
                </key>
                <ref bean="teacherone"></ref>
            </entry>
            <entry>
                <key>
                    <value>10099</value>
                </key>
                <ref bean="teachertwo"></ref>
            </entry>
        </map>
    </property>
</bean>
    <bean id="teacherone" class="com.zzq.spring6.iocxml.dimap.Teacher">
        <property name="teacherId" value="22"></property>
        <property name="teacherName" value="王五"></property>
    </bean>
    <bean id="teachertwo" class="com.zzq.spring6.iocxml.dimap.Teacher">
        <property name="teacherId" value="22"></property>
        <property name="teacherName" value="王五"></property>
    </bean>
</beans>

引入集合类型的bean

1、创建三个对象

2、注入普通类型属性

3、使用util:类型 定义

4、在学生bean引入util:类型定义bean,完成list、map类型属性注入

lesson

package com.zzq.spring6.iocxml.dimap;

public class Lesson {
    private String lessonName;

    @Override
    public String toString() {
        return "Lesson{" +
                "lessonName='" + lessonName + '\'' +
                '}';
    }

    public String getLessonName() {
        return lessonName;
    }

    public void setLessonName(String lessonName) {
        this.lessonName = lessonName;
    }
}
<?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:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/util
        http://www.springframework.org/schema/util/spring-util.xsd
               http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">


    <bean id="student" class="com.zzq.spring6.iocxml.dimap.Student">
        <property name="name" value="lucy"></property>
        <property name="sid" value="111"></property>
<!--        注入list map类型属性-->
        <property name="lessonList" ref="lessonList"></property>
        <property name="teacherMap" ref="teacherMap"></property>
    </bean>
<util:list id="lessonList">
    <ref bean="lessonone"></ref>
    <ref bean="lessontwo"></ref>
</util:list>
    <util:map id="teacherMap">
        <entry>
            <key>
                <value>10001</value>
            </key>
            <ref bean="teacherone"></ref>
        </entry>
        <entry>
            <key>
                <value>1208</value>
            </key>
            <ref bean="teachertwo"></ref>
        </entry>
    </util:map>

    <bean id="lessonone" class="com.zzq.spring6.iocxml.dimap.Lesson">
        <property name="lessonName" value="java开发"></property>
    </bean>
    <bean id="lessontwo" class="com.zzq.spring6.iocxml.dimap.Lesson">
        <property name="lessonName" value="前端开发"></property>
    </bean>
    <bean id="teacherone" class="com.zzq.spring6.iocxml.dimap.Teacher">
        <property name="teacherId" value="2201"></property>
        <property name="teacherName" value="王五"></property>
    </bean>
    <bean id="teachertwo" class="com.zzq.spring6.iocxml.dimap.Teacher">
        <property name="teacherId" value="2200"></property>
        <property name="teacherName" value="刘五"></property>
    </bean>
</beans>

引入p命名空间

<?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:util="http://www.springframework.org/schema/util"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/util
        http://www.springframework.org/schema/util/spring-util.xsd
               http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--p命名空间得到注入-->
    <bean id="studentp" class="com.zzq.spring6.iocxml.dimap.Student"
          p:sid="111" p:name="流水" p:lessonList-ref="lessonList" p:teacherMap-ref="teacherMap">

    </bean>

    <bean id="student" class="com.zzq.spring6.iocxml.dimap.Student">
        <property name="name" value="lucy"></property>
        <property name="sid" value="111"></property>
        <!--        注入list map类型属性-->
        <property name="lessonList" ref="lessonList"></property>
        <property name="teacherMap" ref="teacherMap"></property>
    </bean>
    <util:list id="lessonList">
        <ref bean="lessonone"></ref>
        <ref bean="lessontwo"></ref>
    </util:list>
    <util:map id="teacherMap">
        <entry>
            <key>
                <value>10001</value>
            </key>
            <ref bean="teacherone"></ref>
        </entry>
        <entry>
            <key>
                <value>1208</value>
            </key>
            <ref bean="teachertwo"></ref>
        </entry>
    </util:map>

    <bean id="lessonone" class="com.zzq.spring6.iocxml.dimap.Lesson">
        <property name="lessonName" value="java开发"></property>
    </bean>
    <bean id="lessontwo" class="com.zzq.spring6.iocxml.dimap.Lesson">
        <property name="lessonName" value="前端开发"></property>
    </bean>
    <bean id="teacherone" class="com.zzq.spring6.iocxml.dimap.Teacher">
        <property name="teacherId" value="2201"></property>
        <property name="teacherName" value="王五"></property>
    </bean>
    <bean id="teachertwo" class="com.zzq.spring6.iocxml.dimap.Teacher">
        <property name="teacherId" value="2200"></property>
        <property name="teacherName" value="刘五"></property>
    </bean>
</beans>
package com.zzq.spring6.iocxml.dimap;

import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestStu {
    @Test
    public void testStu(){
        ApplicationContext context=new
                ClassPathXmlApplicationContext("bean-diref.xml");
        Student student = context.getBean("studentp", Student.class);
        student.run();
    }
}

引入外部属性文件

引入依赖

 <!-- MySQL驱动 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.30</version>
</dependency>

<!-- 数据源 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.15</version>
</dependency>

创建外部属性文件

jdbc.user=root
jdbc.password=root
jdbc.url=jdbc:mysql://localhost:3306/spring?serverTimezone=UTC
jdbc.driver=com.mysql.cj.jdbc.Driver

配置bean

<?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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--引入外部属性文件-->
    <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!--    完成数据库信息的注入-->
    <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="${jdbc.url}"></property>
        <property name="username" value="${jdbc.user}"></property>
        <property name="password" value="${jdbc.password}"></property>
        <property name="driverClassName" value="${jdbc.driver}"></property>
    </bean>
</beans>

测试

package com.zzq.spring6.iocxml.jdbc;

import com.alibaba.druid.pool.DruidDataSource;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestJdbc {
    @Test
    public void demo1() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl("jdbc:mysql://localhost:3306/spring?serverTimezone=UTC");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");

    }
    @Test
    public void  demo2(){
        ApplicationContext context=new
                ClassPathXmlApplicationContext("bean-jdbc.xml");
        DruidDataSource dataSource = context.getBean(DruidDataSource.class);
        System.out.println(dataSource.getUrl());
    }
}

bean的作用域

bean的生命周期

package com.zzq.spring6.iocxml.life;

public class User {
    private String name;
//无参构造
    public User() {
        System.out.println("1 bean对象创建,调用无参构造");
    }
//初始化方法
    public void  initMethod(){
        System.out.println("4、bean对象初始化,调用指定的初始化方法");
    }
    //销毁的方法
    public void destroyMethod(){
        System.out.println("7、bean对象销毁,调用指定的销毁方法");
    }
    public String getName() {
        return name;
    }

    public void setName(String name) {
        System.out.println("2 给bean对象设置属性值");
        this.name = name;
    }
}
package com.zzq.spring6.iocxml.life;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.lang.Nullable;

public class MyBeanPost implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    System.out.println("3、bean后置处理器,初始化之前执行");
    System.out.println(beanName+"::"+bean);
        return bean;
    }
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    System.out.println("5、bean后置处理器,初始化之后执行");
    System.out.println(beanName+"::"+bean);
    return bean;
    }
}
package com.zzq.spring6.iocxml.life;

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

public class TestUser {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context=new
                ClassPathXmlApplicationContext("bean-life.xml");
        User user = context.getBean("user", User.class);
        System.out.println("6  bean对象创建完成,可以使用");
        System.out.println(user);
        context.close();//销毁对象
    }
}
<?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="user" class="com.zzq.spring6.iocxml.life.User"
scope="singleton" init-method="initMethod" destroy-method="destroyMethod"
>
    <property name="name" value="lucy"></property>
</bean>
<!--    bean的后置处理器要放入IOC容器才能生效-->
    <bean id="myBeanPost" class="com.zzq.spring6.iocxml.life.MyBeanPost"></bean>
</beans>

FactoryBean

 FactoryBean是Spring提供的一种整合第三方框架的常用机制。和普通的bean不同,配置一个FactoryBean类型的bean,在获取bean的时候得到的并不是class属性中配置的这个类的对象,而是getObject()方法的返回值。通过这种机制,Spring可以帮我们把复杂组件创建的详细过程和繁琐细节都屏蔽起来,只把最简洁的使用界面展示给我们。

将来我们整合Mybatis时,Spring就是通过FactoryBean机制来帮我们创建SqlSessionFactory对象的。

package com.zzq.spring6.iocxml.factorybean;

import org.springframework.beans.factory.FactoryBean;

public class MyFactoryBean implements FactoryBean<User> {
    @Override
    public User getObject() throws Exception {
        return new User();
    }

    @Override
    public Class<?> getObjectType() {
        return User.class;
    }
}
package com.zzq.spring6.iocxml.factorybean;

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

public class TestUser {
    public static void main(String[] args) {
        ApplicationContext context=new
                ClassPathXmlApplicationContext("bean-factorybean.xml");
       User user =(User) context.getBean("user");
        System.out.println(user);
    }
}
package com.zzq.spring6.iocxml.factorybean;

public class User {
}
<?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="user" class="com.zzq.spring6.iocxml.factorybean.MyFactoryBean"></bean>
</beans>

基于xml自动装配

package com.zzq.spring6.iocxml.auto.controller;

import com.zzq.spring6.iocxml.auto.service.UserService;
import com.zzq.spring6.iocxml.auto.service.UserSeviceImpl;

public class UserController {
    private UserService userService;

    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    public void addUser(){
        System.out.println("controller方法执行了");
        //调用service的方法
        userService.addUserService();
//        UserService userService=new UserSeviceImpl();
//        userService.addUserService();
    }
}
package com.zzq.spring6.iocxml.auto.service;

public interface UserService {
    public void addUserService();
}
package com.zzq.spring6.iocxml.auto.service;

import com.zzq.spring6.iocxml.auto.dao.UserDao;
import com.zzq.spring6.iocxml.auto.dao.UserDaoImpl;

public class UserSeviceImpl implements UserService {
    private  UserDao userDao;

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

    @Override
    public void addUserService() {
        System.out.println("userService方法执行了");
        userDao.addUserDao();
//        UserDao userDao=new UserDaoImpl();
//        userDao.addUserDao();
    }
}
package com.zzq.spring6.iocxml.auto.dao;

public class UserDaoImpl implements UserDao {
    @Override
    public void addUserDao(){
        System.out.println("userDao方法执行了");
    }
}
package com.zzq.spring6.iocxml.auto.dao;

import com.zzq.spring6.iocxml.auto.service.UserService;

public interface UserDao {
public void addUserDao();

}
package com.zzq.spring6.iocxml.auto;

import com.zzq.spring6.iocxml.auto.controller.UserController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestUser {
    public static void main(String[] args) {
        ApplicationContext context=new
                ClassPathXmlApplicationContext("bean-auto.xml");
        UserController controller = context.getBean("userController", UserController.class);
        controller.addUser();
    }
}
<?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="userController" class="com.zzq.spring6.iocxml.auto.controller.UserController" autowire="byType"></bean>-->
<!--<bean id="userService" class="com.zzq.spring6.iocxml.auto.service.UserSeviceImpl" autowire="byType"></bean>-->
<!--<bean id="userDao" class="com.zzq.spring6.iocxml.auto.dao.UserDaoImpl"></bean>-->
<!--    根据名称自动装配-->
    <bean id="userController" class="com.zzq.spring6.iocxml.auto.controller.UserController" autowire="byName"></bean>
    <bean id="userService" class="com.zzq.spring6.iocxml.auto.service.UserSeviceImpl" autowire="byName"></bean>
    <bean id="userDao" class="com.zzq.spring6.iocxml.auto.dao.UserDaoImpl"></bean>
</beans>

自动装配方式:byName
>
> byName:将自动装配的属性的属性名,作为bean的id在IOC容器中匹配相对应的bean进行赋值

基于注解管理Bean

开启组件扫描

<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/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--开启组件扫描-->
<context:component-scan base-package="com.zzq"></context:component-scan>
</beans>

情况一:最基本的扫描方式**

```xml
<context:component-scan base-package="com.atguigu.spring6">
</context:component-scan>
```

**情况二:指定要排除的组件**

```xml
<context:component-scan base-package="com.atguigu.spring6">
    <!-- context:exclude-filter标签:指定排除规则 -->
    <!-- 
         type:设置排除或包含的依据
        type="annotation",根据注解排除,expression中设置要排除的注解的全类名
        type="assignable",根据类型排除,expression中设置要排除的类型的全类名
    -->
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
        <!--<context:exclude-filter type="assignable" expression="com.atguigu.spring6.controller.UserController"/>-->
</context:component-scan>
```

**情况三:仅扫描指定组件**

```xml
<context:component-scan base-package="com.atguigu" use-default-filters="false">
    <!-- context:include-filter标签:指定在原有扫描规则的基础上追加的规则 -->
    <!-- use-default-filters属性:取值false表示关闭默认扫描规则 -->
    <!-- 此时必须设置use-default-filters="false",因为默认规则即扫描指定包下所有类 -->
    <!-- 
         type:设置排除或包含的依据
        type="annotation",根据注解排除,expression中设置要排除的注解的全类名
        type="assignable",根据类型排除,expression中设置要排除的类型的全类名
    -->
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    <!--<context:include-filter type="assignable" expression="com.atguigu.spring6.controller.UserController"/>-->
</context:component-scan>
```

bean对象的创建

以上四个注解都可实现bean的创建

package com.zzq.bean;

import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;

@Component(value = "user")//<bean id="user" class="...">属性可不写,默认为user
//@Controller
//@Repository
//@Service
public class User {
}

属性注入

单独使用@Autowired注解,**默认根据类型装配**。【默认是byType】

package com.zzq.autowired.controller;

import com.zzq.autowired.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class UserController {
    //注入service
    //第一种方式属性的注入
    @Autowired//根据类型找到对应对象,完成注入
    private UserService userService;

    public  void add(){
        System.out.println("controller...");
        userService.add();
    }
}
package com.zzq.autowired.service;

import com.zzq.autowired.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService{
    //注入dao

    //第一种方式属性注入
//@Autowired
//    private UserDao userDao;

    //第二种方式set方法注入
//    @Autowired
//    private UserDao userDao;
//
//    public void setUserDao(UserDao userDao) {
//        this.userDao = userDao;
//    }

    //第三种方式:构造方法中注入
  private UserDao userDao;
@Autowired
    public UserServiceImpl(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public void add() {
        System.out.println("service...");
        userDao.add();
    }
}
package com.zzq.autowired.controller;

import com.zzq.autowired.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class UserController {
    //注入service
    //第一种方式属性的注入
//    @Autowired//根据类型找到对应对象,完成注入
//    private UserService userService;

    //第二种方式set方法注入
//    private UserService userService;
//@Autowired
//    public void setUserService(UserService userService) {
//        this.userService = userService;
//    }
    //第三种方式 构造方法的注入
//    private UserService userService;
//@Autowired
//    public UserController(UserService userService) {
//        this.userService = userService;
//    }

    //第四种方式
    private UserService userService;

    public UserController( @Autowired UserService userService) {
        this.userService = userService;
    }

    public  void add(){
        System.out.println("controller...");
        userService.add();
    }
}

@Autowired注解可以出现在:属性上、构造方法上、构造方法的参数上、setter方法上。
- 当带参数的构造方法只有一个,@Autowired注解可以省略。()
- @Autowired注解默认根据类型注入。如果要根据名称注入的话,需要配合@Qualifier注解一起使用。

@Resource注入

@Resource注解也可以完成属性注入。那它和@Autowired注解有什么区别?

- @Resource注解是JDK扩展包中的,也就是说属于JDK的一部分。所以该注解是标准注解,更加具有通用性。(JSR-250标准中制定的注解类型。JSR是Java规范提案。)
- @Autowired注解是Spring框架自己的。
- **@Resource注解默认根据名称装配byName,未指定name时,使用属性名作为name。通过name找不到的话会自动启动通过类型byType装配。**
- **@Autowired注解默认根据类型装配byType,如果想根据名称装配,需要配合@Qualifier注解一起用。**
- @Resource注解用在属性上、setter方法上。
- @Autowired注解用在属性上、setter方法上、构造方法上、构造方法参数上。

@Resource注解属于JDK扩展包,所以不在JDK当中,需要额外引入以下依赖:【**如果是JDK8的话不需要额外引入依赖。高于JDK11或低于JDK8需要引入以下依赖。**】

<dependency>
    <groupId>jakarta.annotation</groupId>
    <artifactId>jakarta.annotation-api</artifactId>
    <version>2.1.1</version>
</dependency>

package com.zzq.resource.controller;

import com.zzq.resource.service.UserService;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller("myUserController")
public class UserController {
    //根据名称进行注入
//@Resource(name = "myUserService")
//private UserService userService;
    //根据类型进行注入
    @Resource
    private UserService userService;

    public  void add(){
        System.out.println("controller...");
       userService.add();
    }
}

Spring全注解开发

package com.zzq.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration//配置类
@ComponentScan("com.zzq")//开启组件扫描
public class SpringConfig {
}
package com.zzq.resource;

import com.zzq.config.SpringConfig;
import com.zzq.resource.controller.UserController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestUserControllerAnno {
    public static void main(String[] args) {
        //加载配置类
       ApplicationContext context=
               new AnnotationConfigApplicationContext(SpringConfig.class);
        UserController controller = context.getBean(UserController.class);
        controller.add();
    }

}

java反射机制

package com.zzq;

import org.junit.jupiter.api.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class TestCar {
    //1、获取clas对象多种方式

    @Test
    public void test01() throws Exception {
//1、类名.class
        Class clazz1 = Car.class;
        //2、对象.getclass()
        Class clazz2 = new Car().getClass();
        //3、Class.forname("全路径")
        Class clazz3 = Class.forName("com.zzq.Car");
//实例化
        Car car = (Car) clazz3.getDeclaredConstructor().newInstance();
        System.out.println(car);
    }

    //2、通过反射获取构造方法
    @Test
    public void test02() throws Exception {
        Class clazz = Car.class;
        //获取所有构造
        Constructor[] constructors = clazz.getConstructors();
        for (Constructor c : constructors) {
            System.out.println("方法个数" + c.getName() + "参数个数" + c.getParameterCount());

        }
        //指定有参数构造创建对象
        //1、构造public
//    Constructor c1=clazz.getConstructor(String.class,int.class, String.class);
//    Car car1 = (Car)c1.newInstance("本部", 10, "黄色");
//    System.out.println(car1);
        //2、构造private
        Constructor c2 = clazz.getDeclaredConstructor(String.class, int.class, String.class);
        c2.setAccessible(true);
        Car car2 = (Car) c2.newInstance("部", 11, "黄色");
        System.out.println(car2);
    }

    //3、获取属性
    @Test
    public void test03() throws Exception {
        Class clazz = Car.class;
        //实例化
        Car car = (Car) clazz.getDeclaredConstructor().newInstance();
        //获取所有的public属性
        //    Field[]fields=clazz.getFields();
        //获取所有属性(包含私有属性)
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            if (field.getName().equals("name")) {
                field.setAccessible(true);
                field.set(car, "奥迪");
            }
            System.out.println(field.getName());
            System.out.println(car);
        }

        }
    //4、获取方法
    @Test
    public void test04() throws Exception {
Car car=new Car("宝马",19,"黑色");
Class clazz=car.getClass();
//public方法
        Method[]methods=clazz.getMethods();
        for (Method m1:methods
             ) {
          //  System.out.println(m1.getName());
            //执行方法toString
            if (m1.getName().equals("toString")){
                String invoke=(String) m1.invoke(car);
              //  System.out.println("toString执行了:"+invoke);
        }
            //private方法
            Method[] methodsAll = clazz.getDeclaredMethods();
            for (Method m:methodsAll){
                if (m.getName().equals("run")){
                    m.setAccessible(true);
                    m.invoke(car);
                }


            }
        }

    }




}

实现Spring的IoC

ApplicationContext.java

package com.zzq.Bean;

import com.zzq.anno.Bean;

public interface ApplicationContext {

    Object getBean(Class clazz);
}

AnnotationApplicationContext.java

package com.zzq.Bean;

import com.zzq.anno.Bean;
import com.zzq.anno.Di;

import java.io.File;
import java.lang.reflect.Field;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class AnnotationApplicationContext implements ApplicationContext {
    //创建map集合,放bean对象
    private   Map<Class, Object> beanFactory = new HashMap<>();
      private static String rootPath;

    //返回对象
    @Override
    public Object getBean(Class clazz) {
        return beanFactory.get(clazz);
    }

    //设置包扫描规则
    //当前包及其子包,拿个类有@Bean注解,把这个类通过反射实例化
     public AnnotationApplicationContext(String basePackage) {
   // public static void pathdemo1(String basePackage) {
        //把.替换成\
        try {
            String packagePath = basePackage.replaceAll("\\.", "\\\\");
            //获取包绝对路径
            Enumeration<URL> urls = Thread.currentThread().getContextClassLoader().getResources(packagePath);
            while (urls.hasMoreElements()) {
                URL url = urls.nextElement();
                String filePath = URLDecoder.decode(url.getFile(), "utf-8");
                //获取包前面路径得到部分,字符串截取
                  rootPath = filePath.substring(0, filePath.length() - packagePath.length());
                //包扫描
                  loadBean(new File(filePath));
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        //属性得到注入
         loadDi();
    }


    //    //包扫描的过程,实例化
   private  void loadBean(File file) throws Exception {
       //1、判断当前是否文件夹
       if (file.isDirectory()) {
           //2、获取文件夹里面所有内容
           File[] childrenFiles = file.listFiles();
           //3、判断文件夹里面为空,直接返回
           if (childrenFiles == null || childrenFiles.length == 0) {
               return;
           }
           //4、如果文件夹里面不为空,遍历文件夹所有内容
           for (File child : childrenFiles) {
               //4.1遍历得到某个File对象,继续判断,如果还是文件,
               if (child.isDirectory()) {
                   //递归
                   loadBean(child);
               } else {
                   //4.2遍历得到File对象不是文件夹,是文件
                   //4.3得到包路径+类名称部分-字符串截取
                   String pathWithClass = child.getAbsolutePath().substring(rootPath.length() - 1);
                   //4.4判断当前文件类型是否.class
                   if (pathWithClass.contains(".class")) {
                       //4.5如果是.class类型,把路径\替换. 把class去掉
                       String allName = pathWithClass.replaceAll("\\\\", ".")
                               .replace(".class", "");
                       //4.6判断类上面是否有注解@Bean,如果有实例化过程
                       //4.6.1获取类发class
                       Class<?> clazz = Class.forName(allName);
                       //4.6.2判断不是接口
                       if (!clazz.isInterface()) {
                           //4.6.3判断类上面是否有注解@Bean
                           Bean annotation = clazz.getAnnotation(Bean.class);
                           if ((annotation != null)) {
                               //4.6.4实例化
                               Object instance = clazz.getConstructor().newInstance();
                               //4.7把对象实例化之后,放到map集合beanFactory
                               //4.7.1判断当前类如果有接口,让接口class作为map的key
                               if (clazz.getInterfaces().length > 0) {
                                   beanFactory.put(clazz.getInterfaces()[0], instance);
                               } else {
                                   beanFactory.put(clazz, instance);
                               }
                           }
                       }
                   }
               }
           }

       }

   }
//属性注入
    private void loadDi()  {
        //实例化对象在beanFactory的map集合里面
        //1、遍历beanFactory的map集合
        Set<Map.Entry<Class,Object>>entries=beanFactory.entrySet();
        for (Map.Entry<Class,Object>entry:entries) {
//2、获取map集合每个对象(value),每个对象属性获取到
            Object obj=entry.getValue();
            //获取对象Class
                Class<?> clazz=obj.getClass();
        //获取每个对象的属性
            Field[] declaredFields = clazz.getDeclaredFields();
            //遍历得到每个对象属性数组,得到每个属性
            for (Field field:declaredFields) {
                //4、判断属性上面是否有@Di注解
                Di annotation = field.getAnnotation(Di.class);
                if (annotation != null) {
                    //如果私有属性,设置可以设置值
                    field.setAccessible(true);
                    //5、如果有@Di注解,把对象进行设置(注入)
                    try {
                        field.set(obj, beanFactory.get(field.getType()));
                    }catch (IllegalAccessException e){
                        throw new RuntimeException(e);
                    }
                }
            }
        }
    }

}
package com.zzq.anno;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Bean {
}
package com.zzq.anno;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Di {
}
package com.zzq;

import com.zzq.Bean.AnnotationApplicationContext;
import com.zzq.Bean.ApplicationContext;
import com.zzq.service.UserService;

public class TestUser {
    public static void main(String[] args)  {
      ApplicationContext context=
              new AnnotationApplicationContext("com.zzq");
        UserService userService  = (UserService)context.getBean(UserService.class);
        System.out.println(userService);
        userService.add();
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱吃java的羊儿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值