spring基础02-IOC容器2-基于xml操作bean管理

2.3 IOC操作Bean管理(基于XML)

2.3.1 什么是Bean管理

  • Bean管理指的是两个操作

    • Spring创建对象

    • Spring注入

2.3.2 创建对象

  • 用maven创建的项目,xml配置文件放在了resources文件夹下,可以直接classpath定位到

  • <?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">
    <!--    配置User对象的创建-->
        <bean id="user" class="com.zhang.User"></bean>
    </beans>
    
  • bean标签的属性:

    • id,唯一标识,
    • class,要创建对象类的全路径,包+类
    • name:和id差不多,属于早期不成熟的一个属性
  • 创建对象时,默认执行的是类的无参构造,所以类必须有无参构造函数

2.3.3注入属性:(DI)

就是依赖注入( DI ) 别别人说DI别不知道是啥

  • 方法1,:使用set方法注入

  • <!--    set方法注入属性-->
    <bean id="book" class="com.zhang.Book">
    	<!--在bean标签中使用property完成属性注入
    		name :类里面的属性名称
    		value:向里面注入的值
    	-->
    	<property name="bname" value="java从入门到放弃"></property>
    </bean>
    
  • 方法2:使用有参数构造进行注入

  • <!--    3.有参构造创建带属性的对象-->
        <bean id="book1" class="com.zhang.Book">
            <constructor-arg name="bname" value="php是最好的编程语言"></constructor-arg>
        </bean>
    
    
  • 方法3: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:p="http://www.springframework.org/schema/p"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <!--    4.是引用p命名空间注入-->
        <bean id="book2" class="com.zhang.Book" p:bname="Spring5冲刺50w"></bean>
    </beans>
    
  • 注意第4行声明p空间

2.3.4 注入其他类型属性

a.字面量

​ 给类的属性设置固定值,就是字面量,

  • null值

    <!--    set方法注入属性-->
        <bean id="book" class="com.zhang.Book">
            <!--在bean标签中使用property完成属性注入
                name :类里面的属性名称
                value:向里面注入的值
            -->
            <property name="bname" value="java从入门到放弃"></property>
            <!--向属性中注入空值-->
            <property name="address">
                <null/>
            </property>
        </bean>
    
  • 属性值包含特殊字符

    <!--向属性中注入特殊符号-->
    <!-- <property name="author" value="<<张>>"></property>这个写法是错的,可能把字符串里面的<>识别为xml结构体 -->
    <property name="author" >
    	<value>
    		<![CDATA[<<张>>]]>
    	</value>
    </property>
    
    • ​ 俩中括号[ [ ] ] ,第一个中括号后面跟CDATA,第二个中括号里面写具体内容
b.注入属性-外部bean
  • 创建service类和dao类

  • Dao类

  • public interface dao {
        public void getUser();
    }
    
    public class MyDao implements dao{
        @Override
        public void getUser() {
            System.out.println("获取user");
        }
    }
    
  • Service类

  • public class MyServices {
        private MyDao myDao;
        public void setMyDao(MyDao myDao) {
            this.myDao = myDao;
        }
    
        public void add(){
            System.out.println("service add");
            myDao.getUser();//调用dao
        }
    }
    
  • 在service里面调用dao里面的方法

    • 配置文件:

    • <bean id="myServices" class="com.zhang.service.MyServices">
          <!--注入属性
                 name:属性名字
                 ref:类类型的属性值-->
          <property name="myDao" ref="myDao"></property>
      </bean>
      
      <bean id="myDao" class="com.zhang.dao.MyDao"></bean>
      
c.注入属性-内部bean和级联属性
  • 一对多关系:部门&员工

    • 部门类和员工类

    • public class Emp {
          private String ename;//员工姓名
          private String gender;//性别
          private Dept dept;
      
          public void setDept(Dept dept) {this.dept = dept;}
          public void setEname(String ename) { this.ename = ename;}
          public void setGender(String gender) {this.gender = gender;}
      }
      
    • public class Dept {
          private String danme;
      
          public void setDanme(String danme) {
              this.danme = danme;
          }
      }
      
    • 配置文件:

    • <bean id="emp" class="com.zhang.bean.Emp">
          <property name="ename" value="张大壮"></property>
          <property name="gender" value="汉子"></property>
      
          <!--设置对象类型属性-->
          <property name="dept">
              <bean id="dept" class="com.zhang.bean.Dept">
                  <property name="danme" value="安保部门"></property>
              </bean>
          </property>
      </bean>
      
    • 测试类

    • @Test
      public void test1(){
          ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
          Emp emp = context.getBean("emp", Emp.class);
          System.out.println(emp.toString());
      }
      
  • 级联赋值:像有关联的类赋值

    • 配置文件:

    • <bean id="emp" class="com.zhang.bean.Emp">
          <property name="ename" value="张大壮"></property>
          <property name="gender" value="汉子"></property>
          <property name="dept"  ref="dept"></property>
          <property name="dept.dname" value="后勤部"></property>
      </bean>
      <bean id="dept" class="com.zhang.bean.Dept"></bean>
      
    • 其他,emp类中加了一个getDept的方法

2.3.5 xml注入集合属性

a.基本注入方式
  • 待操作类

  • public class Stu {
        private String[] courses;//课程
        //测试List类型的属性
        private List<String> list;
        //测试Map类型的属性
        private Map<String,String > map;
        //测试set类型的属性
        private Set<String> set;
    
        public void setSet(Set<String> set) {this.set = set;}
        public void setCourses(String[] courses) {this.courses = courses;}
        public void setList(List<String> list) {this.list = list;}
        public void setMap(Map<String, String> map) {this.map = map;}
    }
    
  • 配置文件

  • <bean id="stu" class="collection.Stu">
        <!-- 数组类型属性注入
            用list或者array都可以-->
        <property name="courses">
            <array>
                <value>java课程</value>
                <value>操作系统</value>
            </array>
        </property>
        <!--   List类型属性     -->
        <property name="list">
            <list>
                <value>工程实践</value>
                <value>la</value>
            </list>
        </property>
    
        <!--map类型-->
        <property name="map">
            <map>
                <entry key="JAVA" value="java"></entry>
            </map>
        </property>
        <!--set类型-->
        <property name="set">
            <set>
                <value>张张张</value>
            </set>
        </property>
    </bean>
    
b.集合里设置对象类型值
  • 配置文件

  • <beans>
        <bean id="stu" class="collection.Stu">
    		<!--    注入list集合类型,值是对象-->
            <property name="courseList">
                <list>
                    <ref bean="java"></ref>
                    <ref bean="database"></ref>
                </list>
            </property>
        </bean>
    
        <bean id="java" class="collection.Course">
            <property name="cname" value="java"></property>
        </bean>
        <bean id="database" class="collection.Course">
            <property name="cname" value="database"></property>
        </bean>
    </beans>
    
  • Stu类和course类

  • public class Course {
        private String cname;//课程名称
        
        public void setCname(String cname) { this.cname = cname;}
    }
    
  • public class Stu {
        private List<Course> courseList;
    
        public void setCourseList(List<Course> courseList) { this.courseList = courseList;}
    }
    
c.把集合注入部分提取出公共部分
  • 在spring配置文件中引入名称空间 util

  • <?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/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
    
  • 多加了一个xmlns:util 同之前p名称的改法,location里面多了两个连接,将原连接里的所有beans改成util

  • 配置文件:

  • <!--提取list集合类型属性注入-->
        <util:list id="bookList">
            <value>钢铁是怎样练成的</value>
            <value>降龙十八掌</value>
        </util:list>
    
    <!--    使用-->
        <bean id="book" class="collection.Book">
            <property name="list" ref="bookList"></property>
        </bean>
    
  • Book类

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

2.3.6 FactoryBean

  • Spring 有两种类型的bean,一种普通的bean,另外一种就是工厂bean
    • 普通bean:在配置文件中定义bean类型就是返回类型
    • 工厂bean:可以不一样
      1. 创建类,让这个类作为工厂bean,实现接口FactoryBean
      2. 实现接口里面的方法,在实现方法中定义返回的bean类型
public class MyBean implements FactoryBean<Course> {
    //定义一下返回的bean的类型
    @Override
    public Course getObject() throws Exception {
        Course course = new Course();
        course.setCname("英语");
        return course;
    }
    @Override
    public Class<?> getObjectType() {
        return null;
    }
    @Override
    public boolean isSingleton() {
        return FactoryBean.super.isSingleton();
    }
}

测试类:

public void test2(){
    ApplicationContext context = new ClassPathXmlApplicationContext("bean-factorybean.xml");
    Course course = context.getBean("mybean", Course.class);
    System.out.println(course);
}

2.3.7 bean作用域

  • 在spring里,设置创建的bean实例是单实例还是多实例

  • 在spring里面,默认情况下创建的bean是一个单实例情况

    • 可以多次context.getbean() ,但是拿出来的对象hashcode都是一个
  • 设置:

    • spring配置文件的bean标签里可以设置scope属性

    • <bean id="book" class="collection.Book" scope="prototype"></bean><!--多实例-->
      bean id="book" class="collection.Book" scope="singleton"></bean><!--单实例:默认的-->
      
    • 设置成singleton时,加载spring配置文件时就会创建单实例对象

    • 设置成prototype时,在调用getBean方法时才创建对象

2.3.8 bean声明周期

  • 一个对象从创建到对象销毁的过程
  • bean的声明周期
    • 第一步:通过构造器创建bean实例(无参构造)
    • 第二步:为bean的属性设置值和对其他bean引用(调用set方法)
    • (后置处理器)把bean的实例传给bean后置处理器的方法postProcessBeforeInitialization
    • 第三步:调用bean的初始化方法(需要进行配置)
    • (后置处理器)把bean的实例传给bean后置处理器的方法postProcessAfterInitialization
    • 第四步:bean可以使用了
    • 第五步:当容器关闭的时候,调用bean的销毁的方法(需要进行配置销毁的方法)

bean类:

public class Order {
    private String oname;
    public void setOname(String oname) {
        this.oname = oname;
        System.out.println("第二步,set方法设置值");
    }
    public Order() {
        System.out.println("第一步,无参构造");
    }
    //创建执行初始化的方法
    public void initMethod(){
        System.out.println("第三部,初始化方法");
    }
    public void destroyMethod(){
        System.out.println("第五步,销毁bean");
    }
}

配置文件:注意配置了初始化方法和销毁方法

<bean id="orders" class="bean.Order" init-method="initMethod" destroy-method="destroyMethod">
    <property name="oname"  value="手机"></property>
</bean>

测试方法,调用了context的close方法

注意:ApplicationContext是个接口,没有close方法, 得强转成new 的ClassPathXmlApplicationContext类型,或者把context声明成这个类型

@Test
public void test3(){
    ApplicationContext context = new ClassPathXmlApplicationContext("bean-factorybean.xml");
    Order orders = context.getBean("orders", Order.class);
    System.out.println("第四步,获取创建bean实例对象");
    System.out.println(orders);
    ((ClassPathXmlApplicationContext)context).close();
}
  • bean的后置处理器
    • 创建类,实现BeanPostProcessor,创建后置处理器
public class PostProcess implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("执行后置处理方法1");

        return bean;
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("执行后置处理方法2");
        return bean;
    }
}

配置文件:

他会为这个配置文件下的每一个bean实例都添加后置处理

<bean id="postprocess" class="bean.PostProcess"></bean>

测试方法:

测试的还是用上一个Order实例

@Test
public void test3(){
    ApplicationContext context = new ClassPathXmlApplicationContext("bean-factorybean.xml");
    Order orders = context.getBean("orders", Order.class);
    System.out.println("第四步,获取创建bean实例对象");
    System.out.println(orders);
    ((ClassPathXmlApplicationContext)context).close();
}

image

2.3.2.9 xml自动装配(一键白学)

  • 啥是手动装配

    • 就是在配置文件里通过value和ref设置每个属性的值
  • 根据指定装配规则(属性名称或者属性类型)Spring自动将匹配的属性进行注入

    • F---K,有这玩意前面十几节学他干毛
  • 根据名称byName

    • 配置文件

    • image

    • bean类

    • public class Emp {
          private Dept dept;
      
          public void setDept(Dept dept) {this.dept = dept;}
          @Override
          public String toString() {return "Emp{" +"dept=" + dept +'}';}
      }
      
    • public class Dept {
          @Override
          public String toString() { return "Dept{}";}
      }
      
    • 测试类测试Emp的创建,略

  • 根据类型:byType

    • 就是去你的配置文件里面找到合适的类型的bean注入,但是注意,必须要保证唯一
    • 比如上面例子要是声明了俩 class="Dept"的bean就不好使了,就必须使用byName了

image

2.3.10 外部属性文件

把一些常用的固定的值,放在一个外部文件中,然后导入xml配置文件

就好像把常量抽取出来组成一个常量类一样

  • 方法1:直接配置数据库信息
    • 配置德鲁伊连接池
    • 引入依赖jar包
<!--    直接配置连接池-->
    <bean id="druid" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306"></property>
        <property name="username" value="root"></property>
        <property name="password" value="072432"></property>
    </bean>
  • 方法2:引入外部属性文件配置数据库连接池

    • 创建外部属性文件,jdbc.properties

    • prop.driverClassName=com.mysql.jdbc.Driver
      prop.url=jdbc:mysql://localhost:3306
      prop.username=root
      prop.password=072432
      
    • 把外部properties属性文件引入到spring配置文件中

      • 引入名称空间context,方法同util空间

      • <?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/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">
        
      • 在spring配置文件中使用标签引入外部属性文件

      • <context:property-placeholder location="jdbc.properties"/>

      • <!--    使用外部属性文件-->
            <context:property-placeholder location="jdbc.properties"/>
            <bean id="druid" class="com.alibaba.druid.pool.DruidDataSource">
                <property name="driverClassName" value="${prop.driverClassName}"></property>
                <property name="url" value="${prop.url}"></property>
                <property name="username" value="${prop.username}"></property>
                <property name="password" value="${prop.password}"></property>
            </bean>
        
posted @ 2022-03-17 20:37  荧惑微光  阅读(30)  评论(0编辑  收藏  举报