Spring IoC

录:

1、spring介绍
2、Spring IoC helloworld
3、依赖注入DI,setter方法注入,构造方法注入
4、bean的实例化方式(三种)
5、Spring 容器类
6、基于xml装配bean---作用域
7、属性注入
8、bean之间的关系
9、p命令空间和SpEL
10、Spring容器中bean的生命周期
11、装配Bean--基于注解Annotation

1、spring介绍    <--返回目录

    * 什么是spring:
        - Spring是一个开放源代码的设计层面框架,他解决的是业务逻辑层和其他各层的松耦合问题,
          因此它将面向接口的编程思想贯穿整个系统应用。Spring是于2003 年兴起的一个轻量级的Java 开发框架,
          由Rod Johnson创建。简单来说,Spring是一个分层的JavaSE/EE full-stack(一站式) 轻量级开源框架。
        - 轻量级:与EJB对比,依赖资源少,消耗的资源少。
        - 分层: 一站式,每一个层都提供的解决方案
            web层:struts,spring-MVC
            service层:spring
            dao层:hibernate,mybatis , jdbcTemplate  --> spring-data
            
    * Spring的核心:控制反转(IoC,Inverse of Control)和面向切面编程(AOP,)
    * IoC意思:将创建对象的控制权反转给了spring,换一句话说就是,以后对象全部由spring创建
    
    * spring的优点
        - 方便解耦,简化开发 (高内聚低耦合)
            Spring就是一个大工厂(容器),可以将所有对象创建和依赖关系维护,交给Spring管理
            spring工厂是用于生成bean
        - AOP编程的支持
            Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能
        - 声明式事务的支持
            只需要通过配置就可以完成对事务的管理,而无需手动编程
        - 方便程序的测试
            Spring对Junit4支持,可以通过注解方便地测试Spring程序
        - 方便集成各种优秀框架
            Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts、Hibernate、MyBatis、Quartz等)的直接支持
        - 降低JavaEE API的使用难度
            Spring 对JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低

  * spring 体系

2、Spring IoC helloworld    <--返回目录

  定义 bean

public class HelloWorld {
    public void sayHi() {
        System.out.println("hello,你好!!!");
    }
}

  beans.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 -->
    <bean id="HelloWorldBeanId" class="com.oy.entity.HelloWorld"/>
    
</beans>

  测试类

package com.oy.test;

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

import com.oy.entity.HelloWorld;

/**
 * HelloWorld演示:
 *         1)编写JavaBean类
 *         2)配置<bean>
 *         3)初始化Spring IoC容器
 *         4)获取bean实例
 * 
 * @author oy
 * @version 1.0
 * @date 2018年12月29日
 * @time 上午1:25:43
 */
class HelloWorldTest {

    @Test
    public void test() {
        // 初始化Spring IoC容器
        ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
        // 根据name获取bean实例
        HelloWorld hw = (HelloWorld)ctx.getBean("HelloWorldBeanId");
        hw.sayHi();
    }

}

3、依赖注入DI,setter方法注入,构造方法注入    <--返回目录

    * DI:Dependency Injection , 依赖注入
    * 什么叫依赖?
        - is a:是一个,继承;子类继承父类==>子类is a 父类
        - has a:有一个,成员变量,依赖。
            public B {
                private A a;  //B类依赖A类
            }
    * 注入:通过setter方法进行另一个对象实例设置
            public B {
                private A a;  //B类依赖A类
                
                public A setA(A a) {
                    this.a = a;     //注入
                }
            }


    * 例如:
        class BookServiceImpl{
            //之前开发:接口 = 实现类  (service和dao耦合)
            //private BookDao bookDao = new BookDaoImpl();
            //spring之后 (解耦:service实现类使用dao接口,不知道具体的实现类,后面使用setter注入实现类)
            private BookDao bookDao;
            setter方法
        }
        
        模拟spring执行过程
        创建service实例:BookService bookService = new BookServiceImpl()    -->IoC  <bean>
        创建dao实例:BookDao bookDao = new BookDaoImple()                    -->IoC
        将dao设置给service:bookService.setBookDao(BookDao);                -->DI   <property>

  People

package com.oy.entity;

/**
 * @author oy
 * @version 1.0
 * @date 2018年12月29日
 * @time 上午7:32:23
 */
public class People {
    private Integer id;
    private String name;
    private Integer age;
    
    public People() {
        System.out.println("调用People的无参构造。。。");
    }
    
    public People(Integer id, String name, Integer age) {
        super();
        System.out.println("调用People的有参构造。。。");
        this.id = id;
        this.name = name;
        this.age = age;
    }
    // getXxx 和 setXxx
}

  PeopleTest

package com.oy.test;

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

import com.oy.entity.People;

/**
 * 2种依赖注入方法:
 *  1.setter方法注入
 *  2.构造方法注入
 *  
 * @author oy
 * @version 1.0
 * @date 2018年12月29日
 * @time 上午7:37:57
 */
public class PeopleTest {
    @SuppressWarnings("resource")
    @Test
    public void test1() {
        // 初始化Spring IoC容器
        ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
        
        // 根据name获取bean实例
        // =====测试依赖注入:setter方法注入=====
        People p = (People)ctx.getBean("people");
        System.out.println(p.getId() + "---" + p.getName() + "---" + p.getAge());
        
        // =====测试依赖注入:构造方法注入=====
        // 通过索引
        People p2 = (People)ctx.getBean("people2");
        System.out.println(p2.getId() + "---" + p2.getName() + "---" + p2.getAge());
        // 通过类型
        People p3 = (People)ctx.getBean("people3");
        System.out.println(p3.getId() + "---" + p3.getName() + "---" + p3.getAge());
        // 通过索引和类型
        People p4 = (People)ctx.getBean("people4");
        System.out.println(p4.getId() + "---" + p4.getName() + "---" + p4.getAge());
    }
}

  beans.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">
    
    <!-- ==========依赖注入:使用setter方法========== -->
    <!-- 装配bean过程:
        IoC容器初始化时,调用People类的无参构造创建bean实例,
        然后调用People类的setter方法给属性注入值
    -->
    <bean id="people" class="com.oy.entity.People">
        <!-- 依赖注入:使用setter方法注入 -->
        <property name="id" value="1"></property>
        <property name="name" value="张三1"></property>
        <property name="age" value="15"></property>
    </bean>
    
    
    <!-- ==========依赖注入:使用构造方法========== -->
    <!-- 装配bean过程:
        IoC容器初始化时,调用People类的有参构造创建bean实例
    -->
    <bean id="people2" class="com.oy.entity.People">
        <!-- 依赖注入:使用有参构造注入 -->
        <!-- 通过索引 -->
        <constructor-arg index="0" value="2"></constructor-arg>
        <constructor-arg index="1" value="李四2"></constructor-arg>
        <constructor-arg index="2" value="25"></constructor-arg>
    </bean>
    
    <bean id="people3" class="com.oy.entity.People">
        <!-- 依赖注入:使用有参构造注入 -->
        <!-- 通过类型 -->
        <constructor-arg type="Integer" value="3"></constructor-arg>
        <constructor-arg type="String" value="李四3"></constructor-arg>
        <constructor-arg type="Integer" value="35"></constructor-arg>
    </bean>

    <bean id="people4" class="com.oy.entity.People">
        <!-- 依赖注入:使用有参构造注入 -->
        <!-- 通过类型和索引 -->
        <constructor-arg index="0" type="Integer" value="4"></constructor-arg>
        <constructor-arg index="1" type="String" value="李四4"></constructor-arg>
        <constructor-arg index="2" type="Integer" value="45"></constructor-arg>
    </bean>
    
</beans>

4、bean的实例化方式(三种)    <--返回目录

  方式一:默认构造 <bean id="" class="">  必须提供默认构造

  方式二:静态工厂

  方式三:实例工厂

   PeopleFactory

package com.oy.entity;

/**
 * 定义了一个非静态工厂
 * @author oy
 * @version 1.0
 * @date 2018年12月29日
 * @time 上午8:10:25
 */

public class PeopleFactory {

    public People createPeople() {
        People p = new People();
        p.setId(5);
        p.setName("李四5");
        p.setAge(55);
        return p;
    }
}

  PeopleStaticFactory

package com.oy.entity;

/**
 * 静态工厂
 * @author oy
 * @version 1.0
 * @date 2018年12月29日
 * @time 上午8:25:21
 */

public class PeopleStaticFactory {
    public static People createPeople() {
        People p = new People();
        p.setId(6);
        p.setName("李四6");
        p.setAge(66);
        return p;
    }
}

  测试类

package com.oy.test;

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

import com.oy.entity.People;

/**
 * bean的实例化方式 :
 *     1.无参构造
 *         <bean id="" class=""> 或 使用setter方法注入属性时都是调用无参构造来实例化bean
 *  2.有参构造
 *      使用构造方法注入属性时调用有参构造
 *  3.非静态工厂
 *  4.静态工厂
 */
public class PeopleTest {
    @SuppressWarnings("resource")
    @Test
    public void test1() {
        // 初始化Spring IoC容器
        ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
        
        // =====测试bean的实例化方式:非静态工厂=====
        People p5 = (People)ctx.getBean("people5");
        System.out.println(p5.getId() + "---" + p5.getName() + "---" + p5.getAge());
        
        // =====测试bean的实例化方式:静态工厂=====
        People p6 = (People)ctx.getBean("people6");
        System.out.println(p6.getId() + "---" + p6.getName() + "---" + p6.getAge());
        
    }
}

  beans.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的实例化方式:使用非静态工厂========== -->
    <bean id="peopleFactory" class="com.oy.entity.PeopleFactory"/>
    <!-- 装配bean过程:
        IoC容器初始化时,调用factory-bean实例的createPeople()方法
    -->
    <bean id="people5" factory-bean="peopleFactory" factory-method="createPeople"/>
      
      <!-- ==========bean的实例化方式:使用静态工厂========== -->
      <!-- 装配bean过程:
        IoC容器初始化时,调用静态工厂的createPeople()方法
    -->
      <bean id="people6" class="com.oy.entity.PeopleStaticFactory" factory-method="createPeople"/>
      
</beans>

5、Spring 容器类    <--返回目录

    * api整体了解,之后不使用,在学习过程需要使用,所以了解即可。
    * BeanFactory :这是一个工厂,用于生成任意bean。
        - 【采取延迟加载,第一次getBean时才会初始化Bean】
    * ApplicationContext:是BeanFactory的子接口,功能更强大。
        - (国际化处理、事件传递、Bean自动装配、各种不同应用层的Context实现)。
        - 【当配置文件被加载,就进行对象实例化】
    * ClassPathXmlApplicationContext 用于加载classpath(类路径、src)下的xml
        加载xml运行时位置 --> /WEB-INF/classes/*.xml
    * FileSystemXmlApplicationContext 用于加载指定盘符下的xml
        一般加载xml运行时位置 --> /WEB-INF/*.xml
        也就是说如果xml文件放在/WEB-INF/*.xml,可以使用FileSystemXmlApplicationContext
            通过java web ServletContext.getRealPath() 获得具体盘符

6、基于xml装配bean---作用域    <--返回目录

    * 作用域:用于确定spring创建bean实例个数
    * 取值:
        - singleton 单例,默认值。
        - prototype 多例,每执行一次getBean将获得一个实例。例如:struts整合spring,配置action多例。
    * 如何配置:<bean id="" class=""  scope="singleton|prototype">

7、属性注入    <--返回目录

public class Dog {
    private String name;
    public Dog() {
        System.out.println("调用Dog的无参构造。。。");
    }
    // getXxx和setXxx
}
public class People {
    private Integer id;
    private String name;
    private Integer age;
    private Dog dog;
    private List<String> hobbies = new ArrayList<String>();
    private Map<String, Object> map = new HashMap<String, Object>();
    private Properties props = new Properties();
    
    public People() {
        System.out.println("调用People的无参构造。。。");
    }
    
    public People(Integer id, String name, Integer age) {
        super();
        System.out.println("调用People的有参构造。。。");
        this.id = id;
        this.name = name;
        this.age = age;
    }
    // getXxx和setXxx
}

  beans.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="people" class="com.oy.entity.People">
        <property name="id" value="1"></property>
        <property name="name" value="张三1"></property>
        <property name="age" value="15"></property>
    </bean>

    <!-- 依赖注入:属性是bean,注入外部bean -->
      <bean id="people2" class="com.oy.entity.People">
        <property name="id" value="1"></property>
        <property name="name" value="张三1"></property>
        <property name="age" value="15"></property>
        <property name="dog" ref="dog"></property>
    </bean>
    <!-- dog配置在people2后面也是可以的 -->
    <bean id="dog" class="com.oy.entity.Dog">
        <property name="name" value="jack"></property>
    </bean>
    
    <!-- 依赖注入:属性是bean,注入内部bean -->
      <bean id="people3" class="com.oy.entity.People">
        <property name="id" value="1"></property>
        <property name="name" value="张三1"></property>
        <property name="age" value="15"></property>
        <property name="dog">
            <bean class="com.oy.entity.Dog">
                <property name="name" value="tom"></property>
            </bean>
        </property>
    </bean>
    
    <!-- 依赖注入:属性是bean,注入null -->
      <bean id="people4" class="com.oy.entity.People">
        <property name="id" value="1"></property>
        <property name="name" value="张三1"></property>
        <property name="age" value="15"></property>
        <property name="dog">
            <null></null>
        </property>
    </bean>
    
    <!-- 依赖注入:属性是List集合 -->
      <bean id="people5" class="com.oy.entity.People">
        <property name="id" value="1"></property>
        <property name="name" value="张三1"></property>
        <property name="age" value="15"></property>
        <property name="hobbies">
            <list>
                <value>吃饭</value>
                <value>睡觉</value>
                <value>打豆豆</value>
            </list>
        </property>
    </bean>
    
    <!-- 依赖注入:属性是Map集合 -->
      <bean id="people6" class="com.oy.entity.People">
        <property name="id" value="1"></property>
        <property name="name" value="张三1"></property>
        <property name="age" value="15"></property>
        <property name="map">
            <map>
                <entry key="key1" value="value1"/>
                <entry key="key2" value="value2"/>
            </map>
        </property>
    </bean>
    
    <!-- 依赖注入:属性是Properties -->
      <bean id="people7" class="com.oy.entity.People">
        <property name="id" value="1"></property>
        <property name="name" value="张三1"></property>
        <property name="age" value="15"></property>
        <property name="props">
            <props>
                <prop key="username">张三</prop>
                <prop key="password">123</prop>
            </props>
        </property>
    </bean>
    
</beans>

  测试类

package com.oy.test;

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

import com.oy.entity.People;

/**
 * 测试依赖注入
 * 属性的类型分为:
 *     1.基本数据类型
 *     2.bean    
 *         通过ref引用注入外部bean
 *         注入内部bean
 *         注入null
 *  3.List集合  (数组Array类似)
 *  4.Map集合
 *  5.Properties类型
 * 
 * @author oy
 * @version 1.0
 * @date 2018年12月29日
 * @time 上午8:57:22
 */
class PeopleTest {

    ApplicationContext ctx = null;
            
    @BeforeEach
    void setUp() throws Exception {
        ctx = new ClassPathXmlApplicationContext("beans.xml");
    }

    /**
     * 依赖注入:属性是基本数据类型
     */
    @Test
    void test1() {
        People p = (People)ctx.getBean("people");
        System.out.println(p.getId() + "---" + p.getName() + "---" + p.getAge());
    }

    /**
     * 依赖注入:属性是bean,注入外部bean
     */
    @Test
    void test2() {
        People p2 = (People)ctx.getBean("people2");
        System.out.println(p2.getId() + "---" + p2.getName() + "---" 
                + p2.getAge() + "---" + p2.getDog().getName());
    }
    
    /**
     * 依赖注入:属性是bean,注入内部bean
     */
    @Test
    void test3() {
        People p3 = (People)ctx.getBean("people3");
        System.out.println(p3.getId() + "---" + p3.getName() + "---" 
                + p3.getAge() + "---" + p3.getDog().getName());
    }
    
    /**
     * 依赖注入:属性是bean,注入null
     */
    @Test
    void test4() {
        People p4 = (People)ctx.getBean("people4");
        System.out.println(p4.getId() + "---" + p4.getName() + "---" 
                + p4.getAge() + "---" + p4.getDog());
    }
    
    /**
     * 依赖注入:属性是List集合
     */
    @Test
    void test5() {
        People p5 = (People)ctx.getBean("people5");
        System.out.println(p5.getId() + "---" + p5.getName() + "---" 
                + p5.getAge() + "---" + p5.getHobbies());
    }
    
    /**
     * 依赖注入:属性是Map集合
     */
    @Test
    void test6() {
        People p6 = (People)ctx.getBean("people6");
        System.out.println(p6.getId() + "---" + p6.getName() + "---" 
                + p6.getAge() + "---" + p6.getMap());
    }
    
    /**
     * 依赖注入:属性是Properties
     */
    @Test
    void test7() {
        People p7 = (People)ctx.getBean("people7");
        System.out.println(p7.getId() + "---" + p7.getName() + "---" + p7.getAge() + "---" 
        + p7.getProps().getProperty("username") + p7.getProps().getProperty("password"));
    }
}

8、bean之间的关系    <--返回目录

public class People {
    private Integer id;
    private String name;
    private Integer age;
    private String className;
    
    public People() {
        System.out.println("调用People的无参构造。。。");
    }
    // getXxx和setXxx
    @Override
    public String toString() {
        return "People [id=" + id + ", name=" + name + ", age=" + age + ", className=" + className + "]";
    }
}
public class User {
    private Integer id;
    private String username;
    private String password;
    
    public User() {
        System.out.println("调用User的无参构造。。。");
    }
    // getXxx和setXxx
    @Override
    public String toString() {
        return "User [id=" + id + ", username=" + username + ", password=" + password + "]";
    }

}

  beans.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之间的关系:继承 -->
    <bean id="peopleParent" class="com.oy.entity.People" abstract="true">
        <property name="age" value="18"></property>
        <property name="className" value="高三1班"></property>
    </bean>
    
    <bean id="zhangsan" parent="peopleParent" depends-on="user">
        <property name="id" value="1"></property>
        <property name="name" value="zhangsan"></property>
        <property name="age" value="19"></property>
    </bean>
    
    <bean id="lisi" parent="peopleParent">
        <property name="id" value="2"></property>
        <property name="name" value="lisi"></property>
    </bean>
    
    <bean id="user" class="com.oy.entity.User">
        <property name="id" value="1"></property>
        <property name="username" value="zhangsan"></property>
        <property name="password" value="123"></property>
    </bean>
    
</beans>

  测试类

package com.oy.test;

import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.oy.entity.People;
import com.oy.entity.User;

/**
 * bean之间的关系:
 *         1.继承
 *             定义抽象bean:<bean id="parent" class="" abstract="true">
 *             继承:<bean id="" parent="parent">
 *             
 *         2.依赖
 *             <bean id="bean1" class="" depends-on="bean2"/>
 *             bean1依赖bean2,bean2必须要在bean1之前初始化
 * 
 *         3.引用  ref
 *             <bean id="" class="">
 *                 <property name="dog" ref="dog"/> 
 *             </bean>
 * 
 * @author oy
 * @version 1.0
 * @date 2018年12月29日
 * @time 上午10:51:26
 */
public class PeopleTest {
    ApplicationContext ctx = null;
    @Before
    public void before() {
        ctx = new ClassPathXmlApplicationContext("beans.xml");
    }

    /**
     * bean之间的关系:继承
     */
    @Test
    public void test1() {
        People zhangsan = (People)ctx.getBean("zhangsan");
        System.out.println(zhangsan);
        
        People lisi = (People)ctx.getBean("lisi");
        System.out.println(lisi);
    }
    
    /**
     * bean之间的关系:依赖
     * Spring IoC容器初始化bean是按配置文件从上到下
     * 需求:假设初始化<bean id="zhangsan">这个bean之前,必须先初始化<bean id="user">,
     *      便认为<bean id="zhangsan">依赖<bean id="user">
     * 配置:<bean id="zhangsan" depends-on="user">
     */
    @Test
    public void test2() {
        People zhangsan = (People)ctx.getBean("zhangsan");
        System.out.println(zhangsan);
        
        People lisi = (People)ctx.getBean("lisi");
        System.out.println(lisi);
        
        User user = (User)ctx.getBean("user");
        System.out.println(user);
        
    }
}

9、p命令空间和SpEL    <--返回目录

public class Address {
    private Integer id;
    private String addrName;
    
    public String fun() {
        return "abc";
    }
    // getXxx和setXxx
}    
public class Customer {
    private String cname = "jack";
    private Double pi;
    private Address address;
    private String addressName;
    private String str;
    // getXxx和setXxx
}
public class Student {
    private Integer id;
    private String name;
    private Integer age;
    private Address address;
    // getXxx和setXxx
}

  beans.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:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="student1" class="com.oy.entity.Student">
        <property name="id" value="1"></property>
        <property name="name" value="张三"></property>
        <property name="age" value="10"></property>
        <property name="address" ref="address"></property>
    </bean>
    
    <!-- 使用P命名空间 -->
    <bean id="student2" class="com.oy.entity.Student" 
        p:id="2" p:name="张三2" p:age="20" p:address-ref="address">
    </bean>
    
    <bean id="address" class="com.oy.entity.Address"
        p:id="1" p:addrName="深圳">
    </bean>
    
    <!-- 使用SpEL -->
    <bean id="customer" class="com.oy.entity.Customer">
        <!-- <property name="cname" value="#{'李四'}"></property> -->
        <!-- 如果customer.cname?为null,不再调用后面方法 -->
        <property name="cname" value="#{customer.cname?.toUpperCase()}"></property>
        <property name="pi" value="#{T(Math).PI}"></property>
        <property name="address" value="#{address}"></property>
        <property name="addressName" value="#{address.addrName}"></property>
        <property name="str" value="#{address.fun()}"></property>
    </bean>
</beans>

  测试类

package com.oy.test;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.oy.entity.Customer;
import com.oy.entity.Student;

/**
 * P命名空间
 *         1)P命名空间使用前提,必须添加命名空间。
 *         2)对"setter方法注入"进行简化,替换<property name="属性名" value/ref="属性值">,
 *         在<bean p:属性名="普通值"  p:属性名-ref="引用值">
 * 
 * SpEL:
 *         1)对<property>进行统一编程,所有的内容都使用value
 *         2)<property name="" value="#{表达式}">
 *             #{123}、#{'jack'} : 数字、字符串
 *             #{beanId} :另一个bean引用
 *            #{beanId.propName}    :操作数据
 *            #{beanId.toString()}    :执行方法
 *            #{T(类).静态字段|静态方法}    :静态方法或字段
 * 
 * @author oy
 * @version 1.0
 * @date 2018年12月30日
 * @time 上午12:15:58
 */
public class StudentTest {
    ClassPathXmlApplicationContext ctx = null;

    @Before
    public void setUp() throws Exception {
        ctx = new ClassPathXmlApplicationContext("beans.xml");
    }

    @After
    public void tearDown() throws Exception {
        ctx.close();
    }

    /**
     * 测试P命名空间
     */
    @Test
    public void test() {
        Student stu1 = (Student)ctx.getBean("student1");
        System.out.println(stu1);
        
        Student stu2 = (Student)ctx.getBean("student2");
        System.out.println(stu2);
    }
    
    /**
     * 测试SpEL
     */
    @Test
    public void test2() {
        Customer customer = (Customer)ctx.getBean("customer");
        System.out.println(customer.getCname());
        System.out.println(customer.getPi());
        System.out.println(customer.getAddress());
        System.out.println(customer.getAddressName());
        System.out.println(customer.getStr());
    }
}

10、Spring容器中bean的生命周期    <--返回目录

    * 1.bean的初始化方法和销毁方法:
    *       容器加载配置文件初始化后,将调用People的无参构造进行bean实例化,
    *       然后调用bean实例的初始化方法  init-method="myInit"。
    *       什么时候调用销毁方法   destroy-method="myDestroy"?容器关闭时,且bean是单例的。
    * 2.BeanPostProcessor接口: 后处理Bean
    *   spring 提供一种机制,只要实现此接口BeanPostProcessor,并将实现类提供给spring容器,
    *      spring容器将自动执行,在容器每个bean的初始化方法前执行before(),在容器每个bean初始化方法后执行after()。
    * 3.模拟Spring IoC实例化bean的过程,即bean的生命周期:

A a =new A();    --> 调用无参构造创建对象

a = B.before(a); --> 将a的实例对象传递给后处理bean,可以生成代理对象并返回。
a.init();          --> 调用bean的初始化方法
a = B.after(a);

a.addUser();      //生成代理对象,目的是在目标方法前后执行(例如:开启事务、提交事务、性能监控)

a.destroy()

   Spring容器中bean的生命周期

1、instantiate bean对象实例化
2、populate properties 封装属性
3、如果Bean实现BeanNameAware 执行 setBeanName
4、如果Bean实现BeanFactoryAware 或者 ApplicationContextAware 设置工厂 setBeanFactory 或者上下文对象 setApplicationContext
5、如果存在类实现 BeanPostProcessor(后处理Bean) ,执行postProcessBeforeInitialization
6、如果Bean实现InitializingBean 执行 afterPropertiesSet 
7、用<bean init-method="myInit"> 指定初始化方法 myInit
8、如果存在类实现 BeanPostProcessor(处理Bean),执行postProcessAfterInitialization
9、执行业务处理(执行目标方法)
10、如果Bean实现 DisposableBean 执行 destroy
11、调用<bean destroy-method="myDestroy"> 指定销毁方法 myDestroy

   IPeople

public interface IPeople {
    public void add();
    public void delete();
}

  People

public class People implements IPeople{
    private Integer id;
    private String name;
    private Integer age;
    private String className;
    
    public People() {
        System.out.println();
        System.out.println("==========调用People无参构造==========");
    }
    
    public void myInit() {
        System.out.println("调用People初始化方法。。。");
    }
    
    public void myDestroy() {
        System.out.println("调用People销毁方法。。。");
    }
    
    @Override
    public void add() {
        System.out.println("调用People目标方法:add()。。。");
        long sum = 0;
        for (int j = 0; j < 1000; j++) {
            sum = 0;
            for (long i = 0; i < 100000; i++) {
                sum += i;
            }
        }
        
        System.out.println(sum);
    }
    
    @Override
    public void delete() {
        System.out.println("调用People目标方法:delete()。。。");
        long sum = 0;
        for (int j = 0; j < 1000; j++) {
            sum = 0;
            for (long i = 0; i < 100000; i++) {
                sum += i;
            }
        }
        System.out.println(sum);
    }
    // getXxx和setXxx
}

  IUserService

public interface IUserService {
    public void add();
    public void delete();
}

  UserServiceImpl

public class UserServiceImpl implements IUserService{
    private Integer id;
    private String username;
    private String password;
    
    public UserServiceImpl() {
        System.out.println();
        System.out.println("==========调用UserServiceImpl无参构造==========");
    }
    
    public void myInit() {
        System.out.println("调用UserServiceImpl初始化方法。。。");
    }
    
    public void myDestroy() {
        System.out.println("调用UserServiceImpl销毁方法。。。");
    }
    
    @Override
    public void add() {
        System.out.println("调用UserServiceImpl目标方法:add()。。。");
    }
    
    @Override
    public void delete() {
        System.out.println("调用UserServiceImpl目标方法:delete()。。。");
    }
    // getXxx和setXxx
}

  StudentService

public interface StudentService {
    void add();
}

  StudentServiceImpl

package com.oy.entity;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class StudentServiceImpl implements StudentService,BeanNameAware,ApplicationContextAware {
    private String beanName;
    private ApplicationContext applicationContext;
    
    // 无参构造
    public StudentServiceImpl() {
        System.out.println();
        System.out.println("==========调用StudentServiceImpl无参构造==========");
    }
    
    // 初始化方法
    public void myInit() {
        System.out.println("调用StudentServiceImpl初始化方法。。。");
    }
    
    // 销毁方法
    public void myDestroy() {
        System.out.println("调用StudentServiceImpl销毁方法。。。");
    }
    
    // 目标方法
    public void add() {
        System.out.println("调用StudentServiceImpl目标方法:add()。。。");
    }

    /**
     * 在bean实例化过程中,调用此方法,将beanName注入给bean实例,
     * 那么可以在此方法外面定义一个属性beanName,将注入的beanName保存起来,
     * 从而其他方法也可以用。
     */
    @Override
    public void setBeanName(String beanName) {
        this.beanName = beanName;
        System.out.println("给StudentServiceImpl注入属性值beanName:" + this.beanName);
    }

    /**
     * 给StudentServiceImpl注入属性值applicationContext。
     * 打印applicationContext类型名称
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
        System.out.println("给StudentServiceImpl注入属性值applicationContext:" + this.applicationContext.getClass().getName());
    }

}

  Spring后处理 BeanPostProcessor 的实现类 BeanPostProcessorImpl

package com.oy.entity;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

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

public class BeanPostProcessorImpl implements BeanPostProcessor {
    
    public BeanPostProcessorImpl() {
        System.out.println();
        System.out.println("==========调用BeanPostProcessorImpl无参构造==========");
    }
    
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("前处理方法,beanName为:" + beanName);
        return bean;
    }

    /**
     * 参数bean:目标对象,即被代理的bean对象
     * 参数beanName:被代理对象的名字,即bean的id属性值
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("后处理方法,bean的类型为:" + bean.getClass().getName());
        
        // 通过beanName过滤,对不同的bean进行处理
        if ("userService".equals(beanName)) {
            // 生成jdk代理
            return Proxy.newProxyInstance(
                    BeanPostProcessorImpl.class.getClassLoader(), 
                    bean.getClass().getInterfaces(), 
                    new InvocationHandler() {
                        
                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                            System.out.println("===开启事务===");
                            Object obj = method.invoke(bean, args);
                            System.out.println("===提交事务===");
                            return obj;
                        }
                        
                    });
        } else if ("people".equals(beanName)) {
            // 生成jdk代理
            return Proxy.newProxyInstance(
                    BeanPostProcessorImpl.class.getClassLoader(), 
                    bean.getClass().getInterfaces(), 
                    new InvocationHandler() {
                        
                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                            
                            //System.out.println(proxy.getClass().getName()); // com.sun.proxy.$Proxy6
                            
                            long start = System.currentTimeMillis();
                            Object obj = method.invoke(bean, args);
                            long time = System.currentTimeMillis() - start;
                            
                            System.out.println("方法" + method.getName() + "()共耗时:" + time + "毫秒");
                            return obj;
                        }
                        
                    });
        } else {
            // 直接返回bean,不生成代理对象
            return bean;
        }      
    }
}

  DisPosableBeanImpl

public class DisPosableBeanImpl implements DisposableBean {
    
    public DisPosableBeanImpl() {
        System.out.println();
        System.out.println("==========调用DisPosableBeanImpl无参构造==========");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("");
        System.out.println("");
        System.out.println("Spring IoC容器关闭。。。");
    }

}

  beans.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="people" class="com.oy.entity.People" init-method="myInit" destroy-method="myDestroy"></bean>
    
    <bean id="userService" class="com.oy.entity.UserServiceImpl" init-method="myInit" destroy-method="myDestroy"></bean>
    
    <bean id="stuServiceId" class="com.oy.entity.StudentServiceImpl" init-method="myInit" destroy-method="myDestroy"></bean>
    
    
    
    
    <!-- 将后处理BeanPostProcessor接口的实现类注册到Spring容器 -->
    <!-- spring将首先初始化该bean,与在xml配置的位置无关 -->
    <bean class="com.oy.entity.BeanPostProcessorImpl"/>
    
    <!-- 将DisPosableBean接口的实现注册到Spring容器 -->
    <bean id="disPosableBeanImpl" class="com.oy.entity.DisPosableBeanImpl"/>
    
</beans>

   测试类

package com.oy.test;

import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.oy.entity.IPeople;
import com.oy.entity.IUserService;

/**
 * bean的生命周期:
 *     1.bean的初始化方法和销毁方法
 *      <bean id="" class="" init-method="" destroy-method=""/>
 *     2.BeanPostProcessor接口: 后处理Bean
 *  
 * @author oy
 * @version 1.0
 * @date 2018年12月29日
 * @time 上午10:51:26
 */
public class PeopleTest {
    ApplicationContext ctx = null;
    @Before
    public void before() {
        ctx = new ClassPathXmlApplicationContext("beans.xml");
    }

    /**
     * 1.bean的初始化方法和销毁方法:
     *       容器加载配置文件初始化后,将调用People的无参构造进行bean实例化,
     *       然后调用bean实例的初始化方法  init-method="myInit"。
     *       什么时候调用销毁方法   destroy-method="myDestroy"?容器关闭时,且bean是单例的。
     * 2.BeanPostProcessor接口: 后处理Bean
     * spring 提供一种机制,只要实现此接口BeanPostProcessor,并将实现类提供给spring容器,
     *      spring容器将自动执行,在容器每个bean的初始化方法前执行before(),在容器每个bean初始化方法后执行after()。
     * 3.模拟Spring IoC实例化bean的过程,即bean的生命周期:
         A a =new A();    --> 调用无参构造创建对象
         
         a = B.before(a); --> 将a的实例对象传递给后处理bean,可以生成代理对象并返回。
         a.init();          --> 调用bean的初始化方法
         a = B.after(a);
        
         a.addUser();      //生成代理对象,目的是在目标方法前后执行(例如:开启事务、提交事务、性能监控)
        
         a.destroy()
     * @throws Exception 
     */
    @Test
    public void test1() throws Exception {
        System.out.println("=======容器初始化完毕=======");
        IPeople p = (IPeople)ctx.getBean("people");
        
        //目标方法
        p.add();
        p.delete();
        
        // 容器关闭时,调用销毁方法   destroy-method="myDestroy",要保证bean是单例的。
        //ctx.getClass().getMethod("close").invoke(ctx);
        // 事实上,close()方法是ClassPathXmlApplicationContext类中提供的
        // 使用多态(子类对象指向父类引用),不能直接调用子类特有的方法
        // 向下强转
        ((ClassPathXmlApplicationContext)ctx).close();
    }
    
    @Test
    public void test2() throws Exception {
        System.out.println("=======容器初始化完毕=======");
        IUserService u = (IUserService)ctx.getBean("userService");
        
        //目标方法
        u.add();
        u.delete();
                
        // 容器关闭时,调用销毁方法   destroy-method="myDestroy",要保证bean是单例的。
        ((ClassPathXmlApplicationContext)ctx).close();
    }
    
}
package com.oy.test;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.oy.entity.StudentService;

/**
 * @author oy
 * @version 1.0
 * @date 2019年1月1日
 * @time 上午3:26:32
 */
public class StudentTest {

    ClassPathXmlApplicationContext ctx = null;
    @Before
    public void setUp() throws Exception {
        ctx = new ClassPathXmlApplicationContext("beans.xml");
    }

    @After
    public void tearDown() throws Exception {
        System.out.println();
        System.out.println("===========销毁IoC容器===========");
        ctx.close();
    }

    /* 测试结果:
        ==========调用BeanPostProcessorImpl无参构造==========

        ==========调用DisPosableBeanImpl无参构造==========
        前处理方法,beanName为:disPosableBeanImpl
        后处理方法,bean的类型为:com.oy.entity.DisPosableBeanImpl
        
        ==========调用People无参构造==========
        前处理方法,beanName为:people
        调用People初始化方法。。。
        后处理方法,bean的类型为:com.oy.entity.People
        
        ==========调用UserServiceImpl无参构造==========
        前处理方法,beanName为:userService
        调用UserServiceImpl初始化方法。。。
        后处理方法,bean的类型为:com.oy.entity.UserServiceImpl
        
        ==========调用StudentServiceImpl无参构造==========
        给StudentServiceImpl注入属性值beanName:stuServiceId
        给StudentServiceImpl注入属性值applicationContext:org.springframework.context.support.ClassPathXmlApplicationContext
        前处理方法,beanName为:stuServiceId
        调用StudentServiceImpl初始化方法。。。
        后处理方法,bean的类型为:com.oy.entity.StudentServiceImpl
        调用StudentServiceImpl目标方法:add()。。。
        
        ===========销毁IoC容器===========
        调用StudentServiceImpl销毁方法。。。
        调用UserServiceImpl销毁方法。。。
        调用People销毁方法。。。
        

        Spring IoC容器关闭。。。
     */
    @Test
    public void test() {
        StudentService studentService = (StudentService)ctx.getBean("stuServiceId");
        studentService.add();
    }

}

11、装配Bean--基于注解Annotation    <--返回目录

  注解使用前提:添加schema命名空间,让spring扫描含有注解的类

<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"><!-- 组件扫描,扫描含有注解的类 base-package:指定包 -->
    <context:component-scan base-package="com.oy"></context:component-scan>
</beans>


  @Component取代<bean class=""/>
       @Component("userDaoid")取代<bean id="userDaoId" class="UserDaoImpl"/>   
       在UserDaoImpl类定义中添加注解@Component("userDaoId")===>这就相当于在配置文件中写了<bean id="userDaoId" class="UserDaoImpl"/>

    * web开发,提供3个@Component注解衍生注解(功能一样)取代<bean class="">
        @Repository :dao层
        @Service:service层
        @Controller:web层
    
    * 依赖注入,给私有字段设置,也可以给setter方法设置
        普通值:@Value("")
        引用值:
            方式1:按照【类型】注入
                @Autowired
            方式2:按照【名称】注入1
                @Autowired
                @Qualifier("名称")
            方式3:按照【名称】注入2
                @Resource[("名称")]
    * 注意:            
        @Resource不写名称,就是根据【类型】注入
        @Resource是JDK提供的,jdk1.5没有
        @Autowired是由spring提供的
        
    * 生命周期
        初始化:@PostConstruct
        销毁:    @PreDestroy
        
    * 作用域
        @Scope("prototype") 多例

原文地址:https://www.cnblogs.com/xy-ouyang/p/13756802.html