zoukankan      html  css  js  c++  java
  • 02Spring5 IOC容器

    概念与原理

    1. 什么是IOC
      1. 控制反转,把对象创建和对象之间的调用过程,交给Spring进行管理
      2. 使用IOC目的:为了降低耦合度
      1. 做入门案例就是IOC实现
    1. IOC底层原理
      1. XML解析,工厂模式,反射
    1. 画图讲解IOC底层原理

    IOC(BeanFactory接口)

    1. IOC思想基于IOC容器完成,IOC容器底层就是对象工厂
    2. Spring提供IOC容器实现的两种方式:(两个接口)
      1. BeanFactory: IOC容器基本实现,是Spring内部的使用接口,不提供开发人员进行使用
      1. *加载配置文件时候不会创建对象,在获取对象(使用)才去创建对象
      1. ApplicationContext: BeanFactory接口的子接口,提供更多更强大的功能,一般由开发人员进行使用
      1. *加载配置文件时候就会把在配置文件对象进行创建
    1. ApplicationContext接口有实现类

    IOC操作Bean管理(概念)

    1. 什么是Bean管理
      1. Bean管理指的是两个操作
      1. Spring创建对象
      2. Spring注入属性
    1. Bean管理操作有两种方式
      1. 基于XML配置文件实现
      2. 基于注解方式实现

    IOC操作Bean管理(基于XML方式)

    1. 基于XML方式创建对象
      1. 在Spring配置文件中,使用Bean标签,标签里面添加对应属性,就可以实现对象创建
      1. ID属性: 唯一标识
      2. class属性: 类全路径(包类路径)
      1. 创建对象的时候,默认也是执行无参数构造方法完成对象创建
    1. 基于XML方式注入属性
      1. DI : 依赖注入,就是注入属性
    1. 第一种注入方式: 使用set方法进行注入

    使用Set方法进行注入

    package com.dance.spring5;
    
    public class Book {
    
        //创建属性
        private String bname;
        private String bauthor;
        //创建属性对应的 set 方法
        public void setBname(String bname) {
            this.bname = bname;
        }
        public void setBauthor(String bauthor) {
            this.bauthor = bauthor;
        }
    
        @Override
        public String toString() {
            return "Book{" +
                    "bname='" + bname + '\'' +
                    ", bauthor='" + bauthor + '\'' +
                    '}';
        }
    
        public static void main(String[] args) {
            Book book = new Book();
            book.setBname("flower");
            System.out.println(book);
        }
    
    
    }

    在Spring配置文件配置对象创建,配置属性注入

    <!--
        name : 属性名
        value : 属性值
        -->
    <bean id="book" class="com.dance.spring5.Book">
      <property name="bname" value="dance" />
    </bean>

    新建测试类

    @Test
    public void testBook(){
    
        // 加载Spring配置文件
        ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("spring.xml");
    
        // 获取Bean
        Book book = classPathXmlApplicationContext.getBean("book", Book.class);
    
        // 调用方法
        System.out.println(book);
    }

    执行结果

    Book{bname='dance', bauthor='null'}
    1. 第二种注入方式:使用有参构造进行注入
      1. 创建类,定义属性,创建属性对应有参数构造方法

    使用有参构造方法进行注入

    package com.dance.spring5;
    
    public class Orders {
    
        //属性
        private String oname;
        private String address;
        //有参数构造
        public Orders(String oname,String address) {
            this.oname = oname;
            this.address = address;
        }
    
        @Override
        public String toString() {
            return "Orders{" +
                    "oname='" + oname + '\'' +
                    ", address='" + address + '\'' +
                    '}';
        }
    
        public static void main(String[] args) {
            Orders orders = new Orders("flower", "北京");
            System.out.println(orders);
        }
    }

    在Spring配置文件中进行配置

    <!-- 有参构造注入属性 -->
    <bean id="orders" class="com.dance.spring5.Orders">
      <constructor-arg name="oname" value="flower"/>
      <constructor-arg name="address" value="北京"/>
    </bean>

    新检测试类

    @Test
    public void testOrders(){
    
        // 加载Spring配置文件
        ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("spring.xml");
    
        // 获取Bean
        Orders orders = classPathXmlApplicationContext.getBean("orders", Orders.class);
    
        // 调用方法
        System.out.println(orders);
    }

    执行结果

    Orders{oname='flower', address='北京'}
    1. P命名空间注入(了解)
      1. 使用P命名空间注入可以简化XML配置方式

    使用P命名空间进行注入

    在配置文件中加入P命名空间的校验

    xmlns:p="http://www.springframework.org/schema/p"

    配置Spring文件

    <!--    使用P命名空间注入-->
    <bean id="ordersP" class="com.dance.spring5.Orders" p:oname="dance" p:address="河北" />

    修改Orders类

    注意:因为P命名空间注入依赖于Set方法所以增加setter and getter

    package com.dance.spring5;
    
    public class Orders {
    
        //属性
        private String oname;
        private String address;
    
        public String getOname() {
            return oname;
        }
    
        public void setOname(String oname) {
            this.oname = oname;
        }
    
        public String getAddress() {
            return address;
        }
    
        public void setAddress(String address) {
            this.address = address;
        }
    
        public Orders() {
        }
    
        //有参数构造
        public Orders(String oname,String address) {
            this.oname = oname;
            this.address = address;
        }
    
        @Override
        public String toString() {
            return "Orders{" +
                    "oname='" + oname + '\'' +
                    ", address='" + address + '\'' +
                    '}';
        }
    
        public static void main(String[] args) {
            Orders orders = new Orders("flower", "北京");
            System.out.println(orders);
        }
    }

    新建测试类

    @Test
    public void testOrdersP(){
    
        // 加载Spring配置文件
        ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("spring.xml");
    
        // 获取Bean
        Orders orders = classPathXmlApplicationContext.getBean("ordersP", Orders.class);
    
        // 调用方法
        System.out.println(orders);
    }

    执行结果

    Orders{oname='dance', address='河北'}

    IOC操作Bean管理(XML注入其他类型属性)

    字面量

    null值

    <bean id="orderType" class="com.dance.spring5.Orders">
      <property name="address">
        <null />
      </property>
    </bean>

    属性值包含特殊符号

    属性值包含特殊符号

    1. 把<>进行转义 < >
    2. 使用CDATA
    <bean id="orderType" class="com.dance.spring5.Orders">
      <property name="address">
        <null />
      </property>
      <property name="oname">
        <!--CDATA-->
        <value><![CDATA[ <<Spring5 API>> ]]></value>
      </property>
    </bean>

    注入属性-外部Bean

    (1)创建两个类 service 类和 dao 类

    (2)在 service 调用 dao 里面的方法

    (3)在 spring 配置文件中进行配置

    新建UserDao

    package com.dance.spring5.dao;
    
    public class UserDao {
        
        public void update(){
            System.out.println("update to database .....");
        }
        
    }

    新建UserService

    package com.dance.spring5.service;
    
    import com.dance.spring5.dao.UserDao;
    
    public class UserService {
    
        public UserDao userDao;
    
        public void add(){
            System.out.println("add......");
            userDao.update();
        }
    
        public void setUserDao(UserDao userDao){
            this.userDao = userDao;
        }
    
    }

    配置Spring文件

    <!-- 创建UserDao -->
    <bean id="userDao" class="com.dance.spring5.dao.UserDao" />
    
    <!-- 创建UserService -->
    <bean id="userService" class="com.dance.spring5.service.UserService">
      <!-- 采用ref引用已有的Bean -->
      <property name="userDao" ref="userDao" />
    </bean>

    新建测试类

    @Test
    public void testUserService(){
    
        // 加载Spring配置文件
        ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("spring.xml");
    
        // 获取Bean
        UserService userService = classPathXmlApplicationContext.getBean("userService", UserService.class);
    
        // 调用方法
        userService.add();
    }

    执行结果

    add......
    update to database .....

    注入属性-内部Bean

    (1)一对多关系:部门和员工 一个部门有多个员工,一个员工属于一个部门 部门是一,员工是多

    (2)在实体类之间表示一对多关系,员工表示所属部门,使用对象类型属性进行表示

    新建部门类

    package com.dance.spring5;
    
    public class Dept {
    
        private String dname;
    
        public void setDname(String dname) {
            this.dname = dname;
        }
    
        @Override
        public String toString() {
            return "Dept{" +
                    "dname='" + dname + '\'' +
                    '}';
        }
    }

    新建员工类

    package com.dance.spring5;
    
    public class Emp {
    
        private String ename;
    
        private String gender;
    
        private Dept dept;
    
        public void setEname(String ename) {
            this.ename = ename;
        }
    
        public void setGender(String gender) {
            this.gender = gender;
        }
    
        public void setDept(Dept dept) {
            this.dept = dept;
        }
    
        @Override
        public String toString() {
            return "Emp{" +
                    "ename='" + ename + '\'' +
                    ", gender='" + gender + '\'' +
                    ", dept=" + dept +
                    '}';
        }
    }

    配置Spring文件

    <bean id="emp" class="com.dance.spring5.Emp">
      <property name="ename" value="flower" />
      <property name="gender" value="男" />
      <property name="dept">
        <bean id="dept" class="com.dance.spring5.Dept">
          <property name="dname" value="研发部" />
        </bean>
      </property>
    </bean>

    新建测试类

    @Test
    public void testEmp(){
    
        // 加载Spring配置文件
        ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("spring.xml");
    
        // 获取Bean
        Emp emp = classPathXmlApplicationContext.getBean("emp", Emp.class);
    
        // 调用方法
        System.out.println(emp);
    }

    执行结果

    Emp{ename='flower', gender='男', dept=Dept{dname='研发部'}}

    注入属性-级联赋值

    第一种写法

    <bean id="dept2" class="com.dance.spring5.Dept">
      <property name="dname" value="研发部" />
    </bean>
    <bean id="emp2" class="com.dance.spring5.Emp">
      <property name="ename" value="dance" />
      <property name="gender" value="女" />
      <property name="dept" ref="dept2" />
    </bean>

    第二种写法

    emp类增加get方法

    public Dept getDept() {
        return dept;
    }
    <bean id="emp3" class="com.dance.spring5.Emp">
      <property name="ename" value="dance" />
      <property name="gender" value="女" />
      <property name="dept" ref="dept2" />
      <property name="dept.dname" value="财务部" />
    </bean>

    IOC操作Bean管理(xml注入集合属性)

    XML注入集合属性

    • 注入数组类型属性
    • 注入List集合类型属性
    • 注入Map集合类型属性

    新建学生类

    package com.dance.spring.learn.collection;
    
    import java.util.Arrays;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    public class Stu {
        //1 数组类型属性
        private String[] courses;
        //2 list 集合类型属性
        private List list;
        //3 map 集合类型属性
        private Map<String,String> maps;
        //4 set 集合类型属性
        private Set sets;
        public void setSets(Set sets) {
            this.sets = sets;
        }
        public void setCourses(String[] courses) {
            this.courses = courses;
        }
        public void setList(List list) {
            this.list = list;
        }
        public void setMaps(Map<String, String> maps) {
            this.maps = maps;
        }
    
        @Override
        public String toString() {
            return "Stu{" +
                    "courses=" + Arrays.toString(courses) +
                    ", list=" + list +
                    ", maps=" + maps +
                    ", sets=" + sets +
                    '}';
        }
    }

    在Spring中进行配置

    <bean id="stu" class="com.dance.spring.learn.collection.Stu">
        <!--        数组-->
        <property name="courses">
            <array>
                <value>Java</value>
                <value>Spring</value>
            </array>
        </property>
        <!--        集合-->
        <property name="list">
            <list>
                <value>IOC</value>
                <value>AOP</value>
            </list>
        </property>
        <!--        Set-->
        <property name="sets">
            <set>
                <value>Mysql</value>
                <value>Oracle</value>
            </set>
        </property>
        <!--        map-->
        <property name="maps">
            <map>
                <entry key="name" value="flower" />
                <entry key="age" value="21" />
            </map>
        </property>
    </bean>

    新建测试类

    @Test
    public void test1(){
    
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("Spring.xml");
    
        Stu stu = applicationContext.getBean("stu", Stu.class);
    
        System.out.println(stu);
    
    }

    执行结果

    Stu{courses=[Java, Spring], list=[IOC, AOP], maps={name=flower, age=21}, sets=[Mysql, Oracle]}

    在集合中设置对象类型值

    新建课程类

    package com.dance.spring.learn.collection;
    
    /**
     * 课程类
     */
    public class Course {
        private String cname;
    
        public String getCname() {
            return cname;
        }
    
        public void setCname(String cname) {
            this.cname = cname;
        }
    
        @Override
        public String toString() {
            return "Course{" +
                    "cname='" + cname + '\'' +
                    '}';
        }
    }

    修改学生类

    package com.dance.spring.learn.collection;
    
    import java.util.Arrays;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    public class Stu {
        //1 数组类型属性
        private String[] courses;
        //2 list 集合类型属性
        private List list;
        //3 map 集合类型属性
        private Map<String,String> maps;
        //4 set 集合类型属性
        private Set sets;
        // 5 list 对象集合
        private List courseList;
    
        public void setCourseList(List courseList) {
            this.courseList = courseList;
        }
    
        public void setSets(Set sets) {
            this.sets = sets;
        }
        public void setCourses(String[] courses) {
            this.courses = courses;
        }
        public void setList(List list) {
            this.list = list;
        }
        public void setMaps(Map<String, String> maps) {
            this.maps = maps;
        }
    
        @Override
        public String toString() {
            return "Stu{" +
                    "courses=" + Arrays.toString(courses) +
                    ", list=" + list +
                    ", maps=" + maps +
                    ", sets=" + sets +
                    ", courseList=" + courseList +
                    '}';
        }
    }

    在Spring中进行配置

    <!--    创建多个Course-->
    <bean id="cs1" class="com.dance.spring.learn.collection.Course">
      <property name="cname" value="语文" />
    </bean>
    <bean id="cs2" class="com.dance.spring.learn.collection.Course">
      <property name="cname" value="数学" />
    </bean>
    
    <bean id="stu" class="com.dance.spring.learn.collection.Stu">
      <!--        数组-->
      <property name="courses">
        <array>
          <value>Java</value>
          <value>Spring</value>
        </array>
      </property>
      <!--        集合-->
      <property name="list">
        <list>
          <value>IOC</value>
          <value>AOP</value>
        </list>
      </property>
      <!--        Set-->
      <property name="sets">
        <set>
          <value>Mysql</value>
          <value>Oracle</value>
        </set>
      </property>
      <!--        map-->
      <property name="maps">
        <map>
          <entry key="name" value="flower" />
          <entry key="age" value="21" />
        </map>
      </property>
      <!--        list Object-->
      <property name="courseList">
        <list>
          <ref bean="cs1" />
          <ref bean="cs2" />
        </list>
      </property>
    </bean>

    测试

    使用之前的测试类

    执行结果

    Stu{courses=[Java, Spring], list=[IOC, AOP], maps={name=flower, age=21}, sets=[Mysql, Oracle], courseList=[Course{cname='语文'}, Course{cname='数学'}]}

    提取集合注入部分

    新建书类

    package com.dance.spring.learn.collection;
    
    import java.util.List;
    
    public class Book {
        
        private List books;
    
        public void setBooks(List books) {
            this.books = books;
        }
    
        @Override
        public String toString() {
            return "Book{" +
                    "books=" + books +
                    '}';
        }
    }

    在Spring中进行配置

    增加命名空间

    xmlns:util="http://www.springframework.org/schema/util"
    http://www.springframework.org/schema/util
           http://www.springframework.org/schema/util/spring-util.xsd

    配置bookList

    <util:list id="bookList">
      <value>Java</value>
      <value>C++</value>
      <value>Go</value>
    </util:list>
    
    <bean id="book" class="com.dance.spring.learn.collection.Book">
      <property name="books" ref="bookList" />
    </bean>

    新建测试类

    @Test
    public void test2(){
    
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("Spring.xml");
    
        Book book = applicationContext.getBean("book", Book.class);
    
        System.out.println(book);
    
    }

    执行结果

    Book{books=[Java, C++, Go]}

    IOC操作Bean管理(FactoryBean)

    1. Spring有两种类型Bean,一种普通Bean,另外一种是工厂Bean(FactoryBean)

    普通Bean

    在配置文件中定义Bean的类型就是返回类型

    创建MyBean类

    package com.dance.spring.learn.factorybean;
    
    public class MyBean {
    
        public void speak(){
            System.out.println("哈哈哈");
        }
    
    }

    在Spring中配置

    <bean id="myBean" class="com.dance.spring.learn.factorybean.MyBean" />

    新建测试类

    @Test
    public void test3(){
    
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("Spring.xml");
    
        MyBean myBean = applicationContext.getBean("myBean", MyBean.class);
    
        myBean.speak();
    
    }

    执行结果

    哈哈哈

    工厂Bean

    在配置文件定义Bean类型可以和返回类型不一致

    修改MyBean

    实现FactoryBean接口,泛型为Course

    实现接口里面的方法,在实现的方法中定义返回的 bean 类型

    package com.dance.spring.learn.factorybean;
    
    import com.dance.spring.learn.collection.Course;
    import org.springframework.beans.factory.FactoryBean;
    
    public class MyBean implements FactoryBean {
    
        public void speak(){
            System.out.println("哈哈哈");
        }
    
        @Override
        public Course getObject() throws Exception {
            Course course = new Course();
            course.setCname("JDOS实战");
            return course;
        }
    
        @Override
        public Class<?> getObjectType() {
            return null;
        }
    
        @Override
        public boolean isSingleton() {
            return FactoryBean.super.isSingleton();
        }
    }

    测试

    使用普通Bean的测试

    org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'myBean' is expected to be of type 'com.dance.spring.learn.factorybean.MyBean' but was actually of type 'com.dance.spring.learn.collection.Course'
    
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:395)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:207)
        at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1114)
        at com.dance.spring.learn.testdemo.TestSpring5Demo.test3(TestSpring5Demo.java:39)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
        at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
        at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
        at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
        at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
        at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
        at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
        at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
        at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
        at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
        at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
        at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
        at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
        at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)

    显示类型错误

    修改测试类

    @Test
    public void test3(){
    
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("Spring.xml");
    
        Course myBean = applicationContext.getBean("myBean", Course.class);
    
        System.out.println(myBean);
    
    }

    执行结果

    Course{cname='JDOS实战'}

    IOC操作Bean管理(Bean的作用域)

    Bean的默认作用域

    新建测试类

    去掉Book类的toString方法

    package com.dance.spring.learn.collection;
    
    import java.util.List;
    
    public class Book {
    
        private List books;
    
        public void setBooks(List books) {
            this.books = books;
        }
    
    }

    新建单元测试

    @Test
    public void test4(){
    
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("Spring.xml");
    
        Book book1 = applicationContext.getBean("book", Book.class);
        Book book2 = applicationContext.getBean("book", Book.class);
    
        System.out.println(book1);
        System.out.println(book2);
    
    }

    执行结果

    com.dance.spring.learn.collection.Book@2a40cd94
    com.dance.spring.learn.collection.Book@2a40cd94

    通过执行结果可以看出,在Spring中Bean的作用域默认是单例的

    设置Bean的作用域

    1. 在Spring配置文件Bean标签里面有属性(Scope)用于设置单实例还是多实例
    2. Scope属性值
      1. 第一个值 默认值,singleton, 表示单实例对象
      2. 第二个值, prototype, 表示是多实例对象
    1. Singleton和Prototype的区别
      1. singleton 单实例, prototype 多实例
      2. 设置scope值为singleton时,加载Spring配置文件时就会创建单实例对象,设置scope值为prototype时,不是在加载Spring配置文件时候创建对象,在调用getBean方法时,才会创建多实例对象(就是每次New一个新的)

    其他的我记得还有

    request和session

    request:一次请求

    session:一次会话

    想详细了解的话可以看一下:https://blog.csdn.net/kongmin_123/article/details/82048392

    我感觉写的很好,但是一般没啥用,一般使用的话都是单例的,也就是默认的,在SpringBoot中也都是单例使用的

    修改Spring配置

    修改为多实例对象

    <bean id="book" class="com.dance.spring.learn.collection.Book" scope="prototype">
      <property name="books" ref="bookList" />
    </bean>

    使用Test4测试

    就是上面默认作用域的测试类

    执行结果

    com.dance.spring.learn.collection.Book@2a40cd94
    com.dance.spring.learn.collection.Book@f4168b8

    通过结果可以看出,对象的内存地址不一样,所以是多实例对象

    IOC操作Bean管理(Bean的生命周期)

    生命周期

    从对象创建到对象销毁的过程

    Bean的生命周期

    1. 通过构造器创建Bean实例(无参数构造)
    2. 为Bean的属性设置值和对其他Bean的引用(调用Set方法)
    1. 调用Bean的初始化方法(需要进行配置初始化方法)
    2. Bean可以使用了(对象获取到了)
    1. 当容器关闭时,调用Bean的销毁方法(需要进行配置销毁的方法)

    生命周期样例

    新建Orders类

    package com.dance.spring.learn.factorybean;
    
    public class Orders {
    
        private String oname;
    
        public Orders() {
            System.out.println("生命周期调用链: 第一步");
        }
    
        public void setOname(String oname) {
            this.oname = oname;
            System.out.println("生命周期调用链: 第二步");
        }
    
    
        public void init(){
            System.out.println("生命周期调用链: 第三步");
        }
    
        public void destroy(){
            System.out.println("生命周期调用链: 第五步");
        }
    
    }

    在Spring中配置

    <bean id="orders" class="com.dance.spring.learn.factorybean.Orders" init-method="init" destroy-method="destroy">
      <property name="oname" value="啊哈哈哈~" />
    </bean>

    新建测试类

    @Test
    public void test5(){
    
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("Spring.xml");
    
        Orders orders = applicationContext.getBean("orders", Orders.class);
        System.out.println("生命周期调用链: 第四步");
    
        // 手动销毁容器
        applicationContext.close();
    
    }

    执行结果

    生命周期调用链: 第一步
    生命周期调用链: 第二步
    生命周期调用链: 第三步
    生命周期调用链: 第四步
    生命周期调用链: 第五步

    Bean的后置处理器

    后置处理器的生命周期位于初始化第三步的前后,整合后就是7步

    1. 通过构造器创建Bean实例(无参数构造)
    2. 为Bean的属性设置值和对其他Bean的引用(调用Set方法)
    1. 把Bean的实例传递给Bean的后置处理器(postProcessBeforeInitialization)
    2. 调用Bean的初始化方法(需要进行配置初始化方法)
    1. 把Bean的实例传递给Bean的后置处理器(postProcessAfterInitialization)
    2. Bean可以使用了(对象获取到了)
    1. 当容器关闭时,调用Bean的销毁方法(需要进行配置销毁的方法)

    后置处理器样例

    新建后置处理器Bean

    package com.dance.spring.learn.factorybean;
    
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.config.BeanPostProcessor;
    
    public class MyBeanPostProcessor implements BeanPostProcessor {
    
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("生命周期调用链: 第三步之前");
            return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
        }
    
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("生命周期调用链: 第三步之后");
            return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
        }
    }

    在Spring中进行配置

    <bean id="myBeanPostProcessor" class="com.dance.spring.learn.factorybean.MyBeanPostProcessor" />

    测试

    调用Bean的生命周期样例测试

    执行结果

    生命周期调用链: 第一步
    生命周期调用链: 第二步
    生命周期调用链: 第三步之前
    生命周期调用链: 第三步
    生命周期调用链: 第三步之后
    生命周期调用链: 第四步
    生命周期调用链: 第五步

    IOC操作Bean管理(XML自动装配)

    什么是自动装配

    根据指定装配规则(属性名称或者属性类型),Spring自动将匹配的属性值进行注入

    演示自动装配过程

    根据属性名称自动注入

    新建Dept类

    package com.dance.spring.learn.autowire;
    
    public class Dept {
        
    }

    新建Emp类

    package com.dance.spring.learn.autowire;
    
    public class Emp {
    
        private Dept dept;
    
        public void setDept(Dept dept) {
            this.dept = dept;
        }
    
        @Override
        public String toString() {
            return "Emp{" +
                    "dept=" + dept +
                    '}';
        }
    }

    在Spring中进行配置

    <bean id="dept" class="com.dance.spring.learn.autowire.Dept" />
    
    <bean id="emp" class="com.dance.spring.learn.autowire.Emp" autowire="byName">
    </bean>

    byName:根据名称自动注入

    byType:根据类型自动注入

    新建测试类

    @Test
    public void test6(){
    
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("Spring2.xml");
    
        Emp emp = applicationContext.getBean("emp", Emp.class);
    
        System.out.println(emp);
    
    }

    执行结果

    Emp{dept=com.dance.spring.learn.autowire.Dept@25bbf683}

    根据类型自动注入

    在Spring中进行配置

    <bean id="dept" class="com.dance.spring.learn.autowire.Dept" />
    
    <bean id="emp" class="com.dance.spring.learn.autowire.Emp" autowire="byType">
    </bean>

    测试

    使用test6进行测试

    执行结果

    Emp{dept=com.dance.spring.learn.autowire.Dept@3578436e}

    IOC操作Bean管理(外部属性文件)

    直接配置数据库信息

    引入德鲁伊连接池的包

    配置德鲁伊连接池

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
      <property name="driver" value="com.mysql.jdbc.Driver" />
      <property name="url" value="jdbc:mysql://localhost:3306/userDb" />
      <property name="username" value="root" />
      <property name="password" value="123456" />
    </bean>

    引入外部属性文件配置数据库信息

    创建外部属性文件

    在src下创建jdbc.properties

    jdbc.driverClass=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/userDb
    jdbc.username=root
    jdbc.password=123456

    引入Context命名空间

    xmlns:context="http://www.springframework.org/schema/context"
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd

    在Spring中进行配置

    <context:property-placeholder location="classpath:jdbc.properties" />
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
      <property name="driver" value="${jdbc.driverClass}" />
      <property name="url" value="${jdbc.url}" />
      <property name="username" value="${jdbc.username}" />
      <property name="password" value="${jdbc.password}" />
    </bean>

    IOC操作Bean管理(基于注解开发)

    什么是注解

    1. 注解是代码特殊标记,格式:@注解名称 (属性名称=属性值,属性名称=属性值)
    2. 注解作用范围, 类,方法,字段
    1. 使用注解的目的:简化xml配置

    Spring针对Bean管理中创建对象提供的注解

    1. @Component
    2. @Service
    1. @Controller
    2. @Repository

    上面四个注解的功能是一样的,都可用来创建Bean实例

    基于注解的方式创建对象

    引入依赖

    开启注解扫描

    <!-- 
            开启组件扫描
                多包配置可以使用逗号隔开,也可以写父包    
         -->
    <context:component-scan base-package="com.dance.spring.learn.service" />

    创建UserService类

    @Service
    public class UserService {
    
        public void add(){
            System.out.println("add ......");
        }
    
    }

    新建测试类

    @Test
    public void test7(){
        ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("Spring3-annotation.xml");
        UserService userService = classPathXmlApplicationContext.getBean("userService", UserService.class);
        userService.add();
    }

    执行结果

    add ......

    开启组件扫描细节配置

    <!--  
            只扫描@Controller
            use-default-filters="false" : 不使用默认的扫描过滤器
            context:include-filter: 包含过滤器
                type="annotation": 类型为注解
                expression="org.springframework.stereotype.Controller": 只扫描@Controller
        -->
    <context:component-scan base-package="com.dance.spring.learn.service" use-default-filters="false">
      <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
    
    <!--  
            不扫描@Controller
            context:exclude-filter: 排除过滤器
                type="annotation": 类型为注解
                expression="org.springframework.stereotype.Controller": 不扫描@Controller
        -->
    <context:component-scan base-package="com.dance.spring.learn.service">
      <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

    基于注解实现属性注入

    @Autowired

    根据类型进行自动装配

    新建Userdao

    package com.dance.spring.learn.dao;
    
    import org.springframework.stereotype.Repository;
    
    @Repository
    public class UserDao {
    
        public void add(){
            System.out.println("add to db.....");
        }
    
    }

    修改UserService

    package com.dance.spring.learn.service;
    
    import com.dance.spring.learn.dao.UserDao;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    @Service
    public class UserService {
    
        @Autowired
        public UserDao userDao;
        
        public void add(){
            System.out.println("add ......");
            userDao.add();
        }
    
    }

    新建Spring配置文件

    因为之前的已经配置了很多的配置,所以在Src下新建Spring4.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"
           xmlns:util="http://www.springframework.org/schema/util"
           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/util http://www.springframework.org/schema/util/spring-util.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
          ">
        <!--  扫描父包 learn  -->
        <context:component-scan base-package="com.dance.spring.learn"/>
    </beans>

    新建测试类

    @Test
    public void test8(){
        ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("Spring4.xml");
        UserService userService = classPathXmlApplicationContext.getBean("userService", UserService.class);
        userService.add();
    }

    执行结果

    add ......
    add to db.....

    @Qualifier

    需要配合Autowired一期使用,默认为根据类型自动装配,添加@Qualifier后将根据Qualifier的value值进行按名称自动装配

    修改UserService

    package com.dance.spring.learn.service;
    
    import com.dance.spring.learn.dao.UserDao;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.stereotype.Service;
    
    @Service
    public class UserService {
    
        @Autowired
        @Qualifier(value = "userDao")
        public UserDao userDao;
    
        public void add(){
            System.out.println("add ......");
            userDao.add();
        }
    
    }

    测试

    使用test8进行测试

    执行结果

    add ......
    add to db.....

    @Resource

    既可以使用类型注入也可以使用名称注入,默认为名称注入,如果没有相同的名称那么就按类型注入,name和type都指定时,取都符合条件的

    修改UserService

    package com.dance.spring.learn.service;
    
    import com.dance.spring.learn.dao.UserDao;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    
    @Service
    public class UserService {
    
    //    @Autowired
    //    @Qualifier(value = "userDao")
    //    public UserDao userDao;
        
        @Resource
        public UserDao userDao;
    
        public void add(){
            System.out.println("add ......");
            userDao.add();
        }
    
    }

    测试

    使用test8进行测试

    执行结果

    add ......
    add to db.....

    @Value

    用于对普通值进行注入,也可以配合上面的外部属性文件采用${}方式获取配置文件值

    修改UserService

    package com.dance.spring.learn.service;
    
    import com.dance.spring.learn.dao.UserDao;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    
    @Service
    public class UserService {
    
    //    @Autowired
    //    @Qualifier(value = "userDao")
    //    public UserDao userDao;
    
        @Resource
        public UserDao userDao;
        
        @Value(value = "flower")
        public String name;
    
        public void add(){
            System.out.println("add ......:"+name);
            userDao.add();
        }
    
    }

    测试

    使用test8进行测试

    测试结果

    add ......:flower
    add to db.....

    去除XML,纯注解开发

    创建配置类,取代XML

    package com.dance.spring.learn.config;
    
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    @ComponentScan(basePackages = {"com.dance.spring.learn"})
    public class SpringConfig {
    
    }

    新建测试类

    @Test
    public void test9(){
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
        UserService userService = annotationConfigApplicationContext.getBean("userService", UserService.class);
        userService.add();
    }

    执行结果

    add ......:flower
    add to db.....

    完结撒花花

     
     
  • 相关阅读:
    include与php://input执行任意命令
    php Session反序列化漏洞
    php代码审计-file_get_contents()&file_put_contents()
    php代码审计-用户名和密码分开检验
    php -- get_magic_quotes_gpc()函数
    md5(“ffifdyop“,true)
    php弱类型相关
    BurpWeb安全学院之XXE
    ICMP隐藏通信隧道技术
    BurpWeb安全学院之敏感信息泄露
  • 原文地址:https://www.cnblogs.com/flower-dance/p/15685288.html
Copyright © 2011-2022 走看看