Spring框架学习笔记(二):Spring IOC容器配置 Bean,分别基于XML配置bean 和 基于注解配置 bean

Spring 配置/管理 bean 介绍

Bean 管理包括两方面 :创建 bean 对象;给 bean 注入属性

Bean 配置方式:基于 xml 文件配置方式;基于注解方式

基于 XML 配置 bean

2.1 通过类型来获取 bean

方法:给getBean传入一个Class对象

示例:

ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
Monster monster = ioc.getBean(Monster.class);

说明:

(1) 按类型来获取 bean, 要求 ioc 容器中的同一个类的 bean 只能有一个 , 否则会抛出异常
NoUniqueBeanDefinitionException
(2)这种方式的应用场景:比如 XxxAction/Servlet/Controller, XxxService 在一个线程
中只需要一个对象实例 ( 单例 ) 的情况
(3)在容器配置文件 ( 比如 beans.xml) 中给属性赋值 , 底层是通过setter 方法完成的 , 这也是为什么我们需要提供 setter 方法的原因

2.2 通过构造器配置 bean

(1)constructor-arg标签可以指定使用构造器的参数

(2)index表示构造器的第几个参数 从0开始计算的

(3)除了可以通过index 还可以通过 name / type 来指定参数方式,name表示参数的名字,type表示参数的类型

(4)类的构造器,不能有完全相同类型和顺序的构造器,所以可以通过type来指定

<bean id="monster03" class="com.spring.bean.Monster">
    <constructor-arg value="200" index="0"/>
    <constructor-arg value="白骨精" index="1"/>
    <constructor-arg value="吸人血" index="2"/>
</bean>

<bean id="monster04" class="com.spring.bean.Monster">
    <constructor-arg value="200" name="monsterId"/>
    <constructor-arg value="白骨精" name="name"/>
    <constructor-arg value="吸人血" name="skill"/>
</bean>


<bean id="monster05" class="com.spring.bean.Monster">
    <constructor-arg value="300" type="java.lang.Integer"/>
    <constructor-arg value="白骨精~" type="java.lang.String"/>
    <constructor-arg value="吸人血~" type="java.lang.String"/>
</bean>

说明:

  • 通过 index 属性来区分是第几个参数
  • 通过 type 属性来区分是什么类型(按照参数顺序)

2.3 通过 p 名称空间配置 bean

xml 文件配置, 增加命名空间配置

将光标放在p , 输入alt+enter , 就会自动的添加xmlns

示例:

<!--通过p名称空间来配置bean
    将光标放在p , 输入alt+enter , 就会自动的添加xmlns
-->
<bean id="monster06" class="com.spring.bean.Monster"
      p:monsterId="500"
      p:name="红孩儿"
      p:skill="吐火"
/>

2.4 引用/注入外部 bean 对象

在 spring 的 ioc 容器, 可以通过 ref 来实现 bean 对象的相互引用

应用案例:

(1) 创建 MemberDAOImpl.java
public class MemberDAOImpl {
    public MemberDAOImpl() {
        System.out.println("MemberDAOImpl 构造器...");
    }
    public void add() {
        System.out.println("MemberDAOImpl add()方法");
    }
}

(2)建 MemberServiceImpl.java

public class MemberServiceImpl {

    private MemberDAOImpl memberDAO;
    public MemberServiceImpl() {
        System.out.println("MemberServiceImpl 构造器~");
    }
    public void add() {
        System.out.println("MemberServiceImpl add()...");
        memberDAO.add();
    }
    public void setMemberDAO(MemberDAOImpl memberDAO) {
        this.memberDAO = memberDAO;
    }
    public MemberDAOImpl getMemberDAO() {
        return memberDAO;
    }
}

(3)beans.xml 配置

<!-- bean 对象的相互引用
1. 其它含义和前面一样
2. ref 表示 memberDAO 这个属性将引用/指向 id = memberDAOImpl 对象
-->
<bean id="memberServiceImpl" class="com.spring.service.MemberServiceImpl">
    <property name="memberDAO" ref="memberDAOImpl"/>
</bean>
<bean id="memberDAOImpl" class="com.spring.dao.MemberDAOImpl"/>

(5)测试

ApplicationContext ioc = new ClassPathXmlApplicationContext("beans03.xml");
MemberServiceImpl bean = (MemberServiceImpl)ioc.getBean("memberServiceImpl", MemberServiceImpl.class);
System.out.println(bean);

细节说明:

  • 这里就体现出spring容器的依赖注入
  • 注意在spring容器中, xml是作为一个整体来执行的, 即如果你引用到一个bean对象, 对你配置的顺序没有要求,即bean的顺序没有要求
  • 建议还是按顺序,好处是阅读的时候,比较方便

2.5 引用/注入内部 bean 对象

spring ioc 容器中, 可以直接在 bean 内部配置内部 依赖 bean 对象

示例:
<!--配置MemberServiceImpl对象-使用内部bean-->
<bean class="com.spring.service.MemberServiceImpl" id="memberService2">
    <!--自己配置一个内部bean-->
    <property name="memberDAO">
        <bean class="com.spring.dao.MemberDAOImpl"/>
    </property>
</bean>

2.6 引用/注入集合/数组类型

spring ioc 容器, bean 对象的集合/数组类型属性赋值

应用案例:

(1)创建 Master.java

import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

public class Master {

    private String name;
    private List<Monster> monsterList;
    private Map<String, Monster> monsterMap;
    private Set<Monster> monsterSet;
    private String[] monsterName;
    //这个 Properties 是 Hashtable 的子类 , 是 key-value 的形式
//这里 Properties key 和 value 都是 String
    private Properties pros;
    public Master() {
    }
    public Master(String name) {
        this.name = name;
    }
    public Set<Monster> getMonsterSet() {
        return monsterSet;
    }
    public void setMonsterSet(Set<Monster> monsterSet) {

        this.monsterSet = monsterSet;
    }
    public String[] getMonsterName() {
        return monsterName;
    }
    public void setMonsterName(String[] monsterName) {
        this.monsterName = monsterName;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public List<Monster> getMonsterList() {
        return monsterList;
    }

    public void setMonsterList(List<Monster> monsterList) {
        this.monsterList = monsterList;
    }
    public Map<String, Monster> getMonsterMap() {
        return monsterMap;
    }
    public void setMonsterMap(Map<String, Monster> monsterMap) {
        this.monsterMap = monsterMap;
    }
    public Properties getPros() {
        return pros;
    }
    public void setPros(Properties pros) {
        this.pros = pros;
    }
}

(2)配置 beans.xml

<!--配置Master对象
体会 spring 容器配置特点 依赖注入-非常灵活
-->
<bean class="com.spring.bean.Master" id="master">
    <property name="name" value="太上老君"/>
    <!--给list属性赋值-->
    <property name="monsterList">
        <list>
            <!--引用的方法-->
            <ref bean="monster01"/>
            <ref bean="monster02"/>
            <!--内部bean-->
            <bean class="com.spring.bean.Monster">
                <property name="name" value="老鼠精"/>
                <property name="monsterId" value="100"/>
                <property name="skill" value="吃粮食"/>
            </bean>
        </list>
    </property>
    <!--给map属性赋值-->
    <property name="monsterMap">
        <map>
            <entry>
                <key>
                    <value>monster03</value>
                </key>
                <!--这里使用的外部bean,引入-->
                <ref bean="monster03"/>
            </entry>
            <entry>
                <key>
                    <value>monster04</value>
                </key>
                <ref bean="monster04"/>
            </entry>
        </map>
    </property>
    <!--给set属性赋值-->
    <property name="monsterSet">
        <set>
            <ref bean="monster05"/>
            <ref bean="monster06"/>
            <bean class="com.spring.bean.Monster">
                <property name="name" value="金角大王"/>
                <property name="skill" value="吐水"/>
                <property name="monsterId" value="666"/>
            </bean>
        </set>
    </property>
    <!--给数组属性赋值
        array标签中使用 value 还是 bean , ref .. 要根据你的业务决定
    -->
    <property name="monsterName">
        <array>
            <value>小妖怪</value>
            <value>大妖怪</value>
            <value>老妖怪</value>
        </array>
    </property>
    <!--给Properties属性赋值 结构k(String)-v(String)-->
    <property name="pros">
        <props>
            <prop key="username">root</prop>
            <prop key="password">123456</prop>
            <prop key="ip">127.0.0.1</prop>
        </props>
    </property>
</bean>

(3)测试

public static void main(String[] args) {
    ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
    Master master01 = ioc.getBean("master", Master.class);
    //获取 list 集合
    System.out.println("======list=======");
    List<Monster> monster_list = master01.getMonsterList();
    for (Monster monster : monster_list) {
        System.out.println(monster);
    }
    //获取 map 集合
    System.out.println("======map=======");
    Map<String, Monster> monster_map = master01.getMonsterMap();
    Set<Map.Entry<String, Monster>> entrySet = monster_map.entrySet();
    for (Map.Entry<String, Monster> entry : entrySet) {
        System.out.println(entry);
    }
    //获取 properties 集合
    System.out.println("======properties=======");
    Properties pros = master01.getPros();
    String property1 = pros.getProperty("username");
    String property2 = pros.getProperty("password");

    String property3 = pros.getProperty("ip");
    System.out.println(property1 + "\t" + property2 + "\t" + property3);
    //获取数组
    System.out.println("======数组=======");
    String[] monsterName = master01.getMonsterName();
    for (String s : monsterName) {
        System.out.println("妖怪名= " + s);
    }
    //获取 set
    System.out.println("======set=======");
    Set<Monster> monsterSet = master01.getMonsterSet();
    for (Monster monster : monsterSet) {
        System.out.println(monster);
    }
}

运行效果:

细节说明:

(1)主要掌握 List/Map/Properties 三种集合的使用 .
(2)Properties 集合的特点
  • 这个 Properties Hashtable 的子类 , key-value 的形式
  • key string value 也是 string

2.7 通过 util 名称空间创建 list

spring 的 ioc 容器, 可以通过 util 名称空间创建 list

<!--
    通过 util 名称空间来创建 list 集合,可以当做创建 bean 对象的工具来使用
-->
<util:list id="myListBook">
    <value>三国演义</value>
    <value>西游记</value>
    <value>红楼梦</value>
    <value>水浒传</value>
</util:list>
<bean id="bookStore" class="com.spring.bean.BookStore">
    <property name="bookList" ref="myListBook"/>
</bean>

集合

应用案例:

(1)创建 BookStore.java

public class BookStore {//书店
    private List<String> bookList;
    public BookStore() {
    }
    public List<String> getBookList() {
        return bookList;
    }
    public void setBookList(List<String> bookList) {
        this.bookList = bookList;
    }
}

(2)修改 beans.xml , 增加配置

<!--
    通过 util 名称空间来创建 list 集合,可以当做创建 bean 对象的工具来使用
-->
<util:list id="myListBook">
    <value>三国演义</value>
    <value>西游记</value>
    <value>红楼梦</value>
    <value>水浒传</value>
</util:list>
<bean id="bookStore" class="com.spring.bean.BookStore">
    <property name="bookList" ref="myListBook"/>
</bean>

(3)测试

@Test
public void bookStoreTest() {
    ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
    BookStore bookStore = ioc.getBean("bookStore", BookStore.class);
    System.out.println(bookStore.getBookList());
}

2.8 级联属性赋值

spring 的 ioc 容器, 可以直接给对象属性的属性赋值, 即级联属性赋值

应用案例:

(1)创建 Dept.java

public class Dept {
    private String name;
    public Dept() {
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

(2)创建 Emp.java

public class Emp {
    private String name;
    private Dept dept;
    public Emp() {
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Dept getDept() {
        return dept;
    }
    public void setDept(Dept dept) {
        this.dept = dept;
    }
}

(3)修改 beans.xml , 增加配置

<!--配置Dept对象-->
<bean class="com.spring.bean.Dept" id="dept"/>
<!--配置Emp对象-->
<bean class="com.spring.bean.Emp" id="emp">
    <property name="name" value="jack"/>
    <property name="dept" ref="dept"/>
    <!--给dept的name属性指定值[级联属性赋值]-->
    <property name="dept.name" value="Java开发部门"/>
</bean>

2.9 通过静态工厂获取对象

在 spring ioc 容器, 可以通过静态工厂获取 bean 对象

应用案例:

(1)创建 MyStaticFactory.java

import java.util.HashMap;
import java.util.Map;

public class MyStaticFactory {
    private static Map<String, Monster> monsterMap;
    static {
        monsterMap = new HashMap<String, Monster>();
        monsterMap.put("monster_01", new Monster(100, "黄袍怪", "一阳指"));
        monsterMap.put("monster_02", new Monster(200, "九头金雕", "如来神掌"));
    }
    public static Monster getMonster(String key) {
        return monsterMap.get(key);
    }
}

(2)修改 beans.xml , 增加配置

<!-- 通过静态工厂来获取 bean 对象 -->
<bean id="my_monster" class="com.spring.factory.MyStaticFactory"
      factory-method="getMonster">
    <!-- constructor-arg 标签提供 key -->
    <constructor-arg value="monster_01"/>
</bean>

(3)测试

@Test
public void test02() {
    ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
    Monster monster = ioc.getBean("my_monster", Monster.class);
    System.out.println(monster);
}

2.10 通过实例工厂获取对象

在 spring ioc 容器, 可以通过实例工厂获取 bean 对象

 应用案例:

(1)建 MyInstanceFactory.java

import java.util.HashMap;
import java.util.Map;

public class MyInstanceFactory {
    private Map<String, Monster> monster_map;
    //非静态代码块
    {
        monster_map = new HashMap<String, Monster>();
        monster_map.put("monster_01", new Monster(100, "猴子精", "吃人"));
        monster_map.put("monster_02", new Monster(200, "九头金雕", "如来神掌"));
    }
    public Monster getMonster(String key) {
        return monster_map.get(key);
    }
}

(2)配置 beans.xml

<!-- 通过实例工厂来获取 bean 对象 -->
<bean id="myInstanceFactory" class="com.spring.factory.MyInstanceFactory"/>
<bean id="my_monster2" factory-bean="myInstanceFactory"
      factory-method="getMonster">
    <constructor-arg value="monster_02"/>
</bean>

(3)测试代码

@Test
public void getBeanByInstanceFactory() {
    ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
    Monster my_monster = ioc.getBean("my_monster2", Monster.class);
    System.out.println(my_monster);
}

(4)结果

2.11 通过 FactoryBean 获取对象

在 spring ioc 容器,通过 FactoryBean 获取 bean 对象

应用案例:

(1)创建MyFactoryBean.java

说明:

  • 该类实现了 FactoryBean 接口,并指定了泛型Monster
  • 创建了一个map集合,用于存放创建好的对象
  • 重写了getObject方法,返回keyVal对应的对象,即this.monster_map.get(keyVal)
  • 重写了getObjectType方法,返回对象的运行类型
  • 重写isSingleton方法,表示对象是否为单例,true为是
public class MyFactoryBean implements FactoryBean<Monster> {
    private String keyVal;
    private Map<String, Monster> monster_map;
    {
        monster_map = new HashMap<String, Monster>();
        monster_map.put("monster_01", new Monster(100, "黄袍怪", "一阳指"));
        monster_map.put("monster_02", new Monster(200, "九头金雕", "如来神掌"));
    }
    public void setKeyVal(String keyVal) {
        this.keyVal = keyVal;
    }
    @Override
    public Monster getObject() throws Exception {
// TODO Auto-generated method stub
        return this.monster_map.get(keyVal);
    }
    @Override
    public Class getObjectType() {
// TODO Auto-generated method stub
        return Monster.class;
    }
    @Override
    public boolean isSingleton() {
// TODO Auto-generated method stub
        return true;
    }
}

(2)配置 beans.xml

<!--
    1. 通过 FactoryBean 来获取 bean 对象
    2. name="keyVal" 就是 MyFactoryBean 定义的 setKeyVal 方法
    3. value="monster_01" ,就是给 keyVal 的值
-->
<bean id="myFactoryBean" class="com.spring.factory.MyFactoryBean">
    <property name="keyVal" value="monster_01"/>
</bean>

(3)测试代码

@Test
public void getBeanByFactoryBean() {
    ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
    Monster monster = ioc.getBean("myFactoryBean", Monster.class);
    System.out.println(monster);
}

2.12 bean 配置信息重用(继承)

在 spring ioc 容器中, 提供了一种继承的方式来实现 bean 配置信息的重用

应用案例:

(1)配置beans.xml

<!-- 继承的方式来实现 bean 配置信息的重用 -->
<bean id="monster10" class="com.spring.bean.Monster">
    <property name="monsterId" value="10"/>
    <property name="name" value="蜈蚣精"/>
    <property name="skill" value="蜇人"/>
</bean>
<!-- parent="monster10" 就是继承使用了 monster10 的配置信息 -->
<bean id="monster11" class="com.spring.bean.Monster" parent="monster10"/>
<!-- 当我们把某个bean设置为 abstract="true" 这个bean只能被继承,而不能实例化了 -->
<bean id="monster12" class="com.spring.bean.Monster" abstract="true">
    <property name="monsterId" value="12"/>
    <property name="name" value="美女蛇"/>
    <property name="skill" value="吃人"/>
</bean>
<!-- parent="monster12" 就是继承使用了 monster12 的配置信息 -->
<bean id="monster13" class="com.spring.bean.Monster" parent="monster12"/>

说明:

  • 可通过parent="monster10"方式继承其他bean,实现bean 配置信息的重用
  • 把某个bean设置为 abstract="true" ,这个bean只能被继承,而不能实例化了

测试代码:

@Test
public void getBeanByExtends() {
    ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
    Monster monster1 = ioc.getBean("monster11", Monster.class);
    System.out.println(monster1);
    Monster monster2 = ioc.getBean("monster13", Monster.class);
    System.out.println(monster2);
}

2.13 bean 创建顺序

说明:

(1)在 spring ioc 容器, 默认是按照配置的顺序创建 bean 对象

<bean id="student01" class="com.hspedu.bean.Student" />
<bean id="department01" class="com.hspedu.bean.Department" />

会先创建 student01 这个 bean 对象,然后创建 department01 这个 bean 对象

(2)如果这样配置,表示 student01 对象依赖于 department01 对象

<bean id="student01" class="com.hspedu.bean.Student" depends-on="department01"/>
<bean id="department01" class="com.hspedu.bean.Department" />

就会先创建 department01 对象,再创建 student01 对象.

(3)如果使用ref关联两个bean,无需关注配置顺序

说明:spring会先把有关联的对象都创建好,再处理引用关系

案例:

1. 先看下面的配置 , 两个 bean 创建的顺序如下
  • 先创建 id=memberDAOImpl
  • 再创建 id = memberServiceImpl
  • 调用 memberServiceImpl.setMemberDAO() 完成引用

2. 先看下面的配置 , 请问两个 bean 创建的顺序如下
  • 先创建 id = memberServiceImpl
  • 再创建 id=memberDAOImpl
  • 最后调用 memberServiceImpl.setMemberDAO() 完成引用

2.14 bean 对象的单例和多例

在 spring 的 ioc 容器, 默认是按照单例创建的,即配置一个 bean 对象后,ioc 容器只会创建一个 bean 实例。

如果,我们希望 ioc 容器配置的某个 bean 对象,是以多个实例形式创建的则可以通过配置 scope="prototype" 来指定,这样spring在获取对象时才会临时创建该对象,而不是像单例对象一样提前创建好

应用案例:

(1)创建 Car.java

public class cat {
    public cat() {
        System.out.println("cat 构造器");
    }
}

(2)配置 beans.xml

<!-- 
如果希望 ioc 容器配置的某个 bean 对象,
是以多个实例形式创建可以通过配置 scope="prototype" 来指定
-->
<bean name="cat" scope="prototype" class="com.spring.bean.Cat"/>

注:通过注解设置多例,可加入如下注解

@Scope(value = "prototype")

(3)测试代码

@Test
public void getBeanByPrototype() {
    ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
    for (int i = 0; i < 3; i++) {
        Cat cat = ioc.getBean("cat", Cat.class);
        System.out.println(cat);
    }
}

细节说明:

  • 在默认情况下 scope属性是 singleton,在启动容器时, 默认就会创建 , 并放入到 singletonObjects 集合
  • 在ioc容器中, 只有一个这个bean对象
  • 当执行getBean时, 返回的的是同一个对象
  • 如果我们希望每次getBean返回一个新的Bean对象,则可以scope="prototype"
  • 如 果 是 单 例 singleton, 同 时 希 望 在 getBean 时 才 创 建 , 可 以 指 定 懒 加 载
    lazy-init="true" (注意默认是 false)
  • 通常情况下, lazy-init 就使用默认值 false , 在开发看来, 用空间换时间是值得的, 除非
    有特殊的要求.
  • 如果 scope="prototype"  这时你的 lazy-init 属性的值不管是 ture, 还是 false 都是在
    getBean 时候,才创建对象.
  • 多例的id值是一样的

2.15 bean 的生命周期

:bean 对象创建是由 JVM 完成的,依次执行如下方法:

(1)执行构造器
(2)执行 set 相关方法
(3)调用 bean 的初始化的方法(需要配置)
(4)使用 bean
(5)当容器关闭时候,调用 bean 的销毁方法(需要配置)
应用实例

(1)创建 House.java

public class House {
    private String name;
    public House() {
        System.out.println("House() 构造器");
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        System.out.println("House setName()...");
        this.name = name;
    }
    //初始化的方式
    public void init() {
        System.out.println("House init()..");
    }
    //销毁的方法
    public void destory() {
        System.out.println("House destory()..");
    }
}

(2)配置beans.xml,配置 bean 的初始化方法和销毁方法

<!-- 配置 bean 的初始化方法和销毁方法 -->
<bean id="house" class="com.spring.bean.House"
      init-method="init" destroy-method="destory">
    <property name="name" value="北京豪宅"/>
</bean>

注:基于注解的方式指定初始化方法,使用@PostConstruct

@PostConstruct
public void init() {
    System.out.println("House init()..");
}

(3)测试代码

@Test
public void beanLife() {
    ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
    House house = ioc.getBean("house", House.class);
    System.out.println(house);
    //关闭容器
    ((ConfigurableApplicationContext) ioc).close();
}

细节说明:

  • 初始化 init 方法和 destory 方法, 是程序员来指定
  • 销毁方法就是当关闭容器时,才会被调用

2.16 配置 bean 的后置处理器

说明:

(1)在 spring ioc 容器,可以配置 bean 的后置处理器

(2)该处理器/对象会在 bean 初始化方法调用前和初始化方法调用后被调用

(3)程序员可以在后置处理器中编写自己的代码

应用案例:

(1)创 建 后 置处 理 器 MyBeanPostProcessor.java

public class MyBeanPostProcessor implements BeanPostProcessor {
    /**
     * 在 bean 初始化之前完成某些任务
     * @param bean : 就是 ioc 容器返回的 bean 对象, 如果这里被替换会修改,则返
    回的 bean 对象也会被修改
     * @param beanName: 就是 ioc 容器配置的 bean 的名称
     * @return Object: 就是返回的 bean 对象
     */
    public Object postProcessBeforeInitialization(Object bean, String beanName)
            throws BeansException {
// TODO Auto-generated method stub
        System.out.println("postProcessBeforeInitialization 被 调 用 " + beanName + " bean= " + bean.getClass());
        return bean;
    }
    /**
     * 在 bean 初始化之后完成某些任务
     * @param bean : 就是 ioc 容器返回的 bean 对象, 如果这里被替换会修改,则返
    回的 bean 对象也会被修改
     * @param beanName: 就是 ioc 容器配置的 bean 的名称
     * @return Object: 就是返回的 bean 对象
     */
    public Object postProcessAfterInitialization(Object bean, String beanName)
            throws BeansException {
        System.out.println("postProcessAfterInitialization 被调用 " + beanName + " bean= " + bean.getClass());
        return bean;
    }
}

(2)配置beans03.xml

当我们在xml 容器配置文件 配置了 MyBeanPostProcessor,这时后置处理器对象,就会作用在该容器创建的所有Bean对象上

<!-- 配置 bean 的初始化方法和销毁方法 -->
<bean id="house" class="com.spring.bean.House"
      init-method="init" destroy-method="destory">
    <property name="name" value="北京豪宅"/>
</bean>
<!-- bean 后置处理器的配置 -->
<bean id="myBeanPostProcessor" class="com.spring.bean.MyBeanPostProcessor" />

(3)测试代码

@Test
public void testBeanPostProcessor() {
    ApplicationContext ioc = new ClassPathXmlApplicationContext("beans03.xml");
    House house = ioc.getBean("house", House.class);
    System.out.println(house);
    //关闭容器
    ((ConfigurableApplicationContext) ioc).close();
}

疑惑点说明:

  • 怎么执行到这个方法:使用 AOP(反射+动态代理+IO+容器+注解)
  • 有什么用:可以对 IOC 容器中所有的对象进行统一处理 ,比如 日志处理/权限的校/安全的验证/事务管理.
  • 针对容器的所有对象吗:是的=>切面编程特点

2.17 通过属性文件给 bean 注入值

在 spring ioc 容器,通过属性文件给 bean 注入值

应用案例:

(1)resources/ 下创建my.properties

可以在Unicode编码转换 - 站长工具 (chinaz.com)网站将中文转成unicode编码

monsterId=1000
name=\u4e4c\u9f9f\u7cbe
skill=\u7f29\u8116\u5b50

(2)修改 src\beans.xml , 继续完成配置

location="classpath:my.properties" 表示在类路径下的my.properties读取

这时我们的属性值通过${属性名}获取,这里说的 属性名 就是 my.properties文件中的 k=v 的k

<!-- 
    1. 通过属性文件给 bean 注入值, 
    2. 需要导入: xmlns:context 名字空间,并指定属性文件路径
-->
<context:property-placeholder location="classpath:my.properties"/>
<bean id="monster100" class="com.spring.bean.Monster">
    <property name="monsterId" value="${monsterId}"/>
    <property name="name" value="${name}"/>
    <property name="skill" value="${skill}"/>
</bean>

(3)测试代码

@Test
public void setProByProFile() {
    ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
    Monster monster100 = ioc.getBean("monster100", Monster.class);
    System.out.println(monster100);
}

2.18 基于 XML bean 的自动装配

在 spring ioc 容器,可以实现自动装配 bean

应用案例:

(1)创建  OrderDao.java
public class OrderDao {
    public void saveOrder() {
        System.out.println("保存 一个订单...");
    }
}

创建 OrderService.java

public class OrderService {
    private OrderDao orderDao;
    public OrderDao getOrderDao() {
        return orderDao;
    }
    public void setOrderDao(OrderDao orderDao) {
        this.orderDao = orderDao;
    }
}

创建 OrderAction.java

public class OrderAction {
    private OrderService orderService;
    public OrderService getOrderService() {
        return orderService;
    }
    public void setOrderService(OrderService orderService) {
        this.orderService = orderService;
    }
}

(2)配置 beans.xml

根据类型进行自动组装

<!--
    autowire="byType" 表示根据类型进行自动组装.
-->
 <bean id="orderAction" autowire="byType" class="com.spring.action.OrderAction" />
 <bean id="orderService" autowire="byType" class="com.spring.service.OrderService"/>
 <bean id="orderDao" class="com.spring.dao.OrderDao"/>

根据名称进行自动组装

<!--
1. 说明: autowire = "byName" 会自动去找 id 为 setXxxx 后面 Xxxx 的 bean 自动组装.
,如果找到就装配,如果找不到就报错, 比如这里的
2. <bean id="orderAction" autowire="byName" class="com.spring.bean.OrderAction" />
就 会 去 找 OrderAction 类 中 定 义 的 setOrderService 的 id 为 orderService 的
OrderService bean 组装,找到就阻装,找不到就组装失败
-->
<bean id="orderAction" autowire="byName" class="com.spring.action.OrderAction"/>
<bean id="orderService" autowire="byName" class="com.spring.service.OrderService"/>
<bean id="orderDao" class="com.spring.dao.OrderDao"/>

说明:

(1)autowire="byType" 表示 在创建 orderService时通过类型的方式 给对象属性 自动完成赋值/引用

(2)比如OrderService 对象有 private OrderDao orderDao

(3)就会在容器中去找有没有 OrderDao类型对象

(4)如果有,就会自动的装配, 如果是按照 byType 方式来装配, 这个容器中,不能有两个OrderDao类型对象

(5)如果对象没有属性,  autowire就没有必要写

(6)如果设置的是 autowire="byName" 表示通过名字完成自动装配

(7)比如下面的 autowire="byName" class="com.hspedu.spring.service.OrderService"

  • 先看 OrderService 属性 private OrderDao orderDao
  • 再根据这个属性的setXxx()方法的 xxx 来找对象id(而不是根据属性名)
  • public void setOrderDao() 就会找id=orderDao对象来进行自动装配
  • 如果没有就装配失败

2.19 spring el 表达式

(1)Spring Expression Language,Spring 表达式语言,简称 SpEL。支持运行时查询并可以操 作对象。

(2)和 EL 表达式一样,SpEL 根据 JavaBean 风格的 getXxx()setXxx()方法定义的属性访问对象

(3)SpEL 使用#{…}作为定界符,所有在大框号中的字符都将被认为是 SpEL 表达式。

应用案例:

(1)创建 SpELBean.java

public class SpELBean {
    private String name;
    private Monster monster;
    private String monsterName;
    private String crySound;
    private String bookName;
    private Double result;
    public SpELBean() {
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Monster getMonster() {
        return monster;
    }
    public void setMonster(Monster monster) {
        this.monster = monster;
    }
    public String getMonsterName() {
        return monsterName;
    }
    public void setMonsterName(String monsterName) {
        this.monsterName = monsterName;
    }
    public String getCrySound() {
        return crySound;
    }
    public void setCrySound(String crySound) {
        this.crySound = crySound;
    }
    public String getBookName() {
        return bookName;
    }
    public void setBookName(String bookName) {
        this.bookName = bookName;
    }
    public Double getResult() {
        return result;
    }
    public void setResult(Double result) {
        this.result = result;
    }
    public String cry(String sound) {
        return "发出 " + sound + "叫声...";
    }
    public static String read(String bookName) {
        return "正在看 " + bookName;
    }
}

(2)配置 beans.xml

<!-- spring el 表达式 -->
<bean id="spELBean" class="com.spring.bean.SpELBean">
    <!-- sp el 给字面量 -->
    <property name="name" value="#{'小苏'}"/>
    <!-- sp el 引用其它 bean -->
    <property name="monster" value="#{monster01}"/>
    <!-- sp el 引用其它 bean 的属性值 -->
    <property name="monsterName" value="#{monster01.name}"/>
    <!-- sp el 调用普通方法(返回值) 赋值 -->
    <property name="crySound" value="#{spELBean.cry('喵喵的..')}"/>
    <!-- sp el 调用静态方法(返回值) 赋值 -->
    <property name="bookName" value="#{T(com.spring.bean.SpELBean).read(' 天龙八部')}"/>
    <!-- sp el 通过运算赋值 -->
    <property name="result" value="#{89*1.2}"/>
</bean>

<!--配置一个monster对象-->
<bean id="monster01" class="com.spring.bean.Monster">
    <property name="monsterId" value="100"/>
    <property name="name" value="蜈蚣精~"/>
    <property name="skill" value="蜇人~"/>
</bean>

(3)测试代码

@Test
public void setProBySpel() {
    ApplicationContext ioc = new ClassPathXmlApplicationContext("beans04.xml");
    SpELBean spELBean = ioc.getBean("spELBean", SpELBean.class);
    System.out.println(spELBean.getName());
    System.out.println(spELBean.getMonster());
    System.out.println(spELBean.getMonsterName());
    System.out.println(spELBean.getCrySound());
    System.out.println(spELBean.getBookName());
    System.out.println(spELBean.getResult());
}

基于注解配置 bean

3.1 基本介绍

基于注解的方式配置 bean, 主要用于项目开发中的组件,比如 ControllerService、和 Dao.

组件注解的形式有:

(1)@Component 表示当前注解标识的是一个组件

(2)@Controller 表示当前注解标识的是一个控制器,通常用于 Servlet

(3)@Service 表示当前注解标识的是一个处理业务逻辑的类,通常用于 Service

(4)@Repository 表示当前注解标识的是一个持久化层的类,通常用于 Dao

3.2 快速入门案例

使用注解的方式来配置 Controller / Service / Respository / Component

(1)创建 UserAction.java UserService.java, UserDao.java MyComponent.java

/**
 * @Controller 标识该类是一个控制器Controller, 通常这个类是一个Servlet
 */
@Controller
public class UserAction {}
/**
 * @Service 标识该类是一个Service类/对象
 */
@Service
public class UserService {
}
/**
 * 使用 @Repository 标识该类是一个Repository是一个持久化层的类/对象
 */
@Repository
public class UserDao {
}
/**
 * @Component 标识该类是一个组件, 是一个通用的注解
 */
@Component
public class MyComponent {
}

(2)在xml文件中配置要扫描的包

<!--配置容器要扫描的包
1. component-scan 要对指定包下的类进行扫描, 并创建对象到容器
2. base-package 指定要扫描的包
3. 含义是当spring容器创建/初始化时,就会扫描com.spring.component包
   下的所有的 有注解 @Controller / @Service / @Respository / @Component类
   将其实例化,生成对象,放入到ioc容器
-->
<context:component-scan base-package="com.spring.component"/>

(3)测试代码

@Test
public void getBeanByAnnotation() {
    ApplicationContext ioc = new ClassPathXmlApplicationContext("beans05.xml");
    UserAction userAction = ioc.getBean(UserAction.class);
    System.out.println(userAction);
    UserDao userDao = ioc.getBean(UserDao.class);
    System.out.println(userDao);
    MyComponent myComponent = ioc.getBean(MyComponent.class);
    System.out.println(myComponent);
    UserService userService = ioc.getBean(UserService.class);
    System.out.println(userService);
}

运行结果:

 (5)细节说明:

  • 必须在 Spring 配置文件中指定"自动扫描的包"IOC 容器才能够检测到当前项目中哪些类被标识了注解, 注意到导入 context 名称空间。可以使用通配符 * 来指定 ,比如 com.spring.* 表示。
<!-- 配置自动扫描的包 -->
<context:component-scan base-package="com.spring.component" />
  • Spring IOC 容器不能检测一个使用了 @Controller 注解的类到底是不是一个真正的控
    制器。注解的名称是用于程序员自己识别当前标识的是什么组件。其它的 @Service
    @Repository 也是一样的道理( 也就是说 spring IOC 容器只要检查到注解就会生成对象,
    但是这个注解的含义 spring 不会识别,注解是给程序员编程方便看的)
  • <context:component-scan base-package="com.hspedu.spring.component" resource-pattern="User*.class" />,resource-pattern="User*.class": 表示只扫描com.spring.component 和它的子包下的User打头的类
  • 排除指定类

如果我们希望排除某个包/子包下的某种类型的注解,可以通过exclude-filter来指定

(1)context:exclude-filter 指定要排除哪些类
(2)type 指定排除方式 ,annotation表示按照注解来排除
(3)expression="org.springframework.stereotype.Service" 指定要排除的注解的全路径

<context:component-scan base-package="com.spring.component">
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>

以上配置表示不扫描带Service和Repository注解的类

  • 扫描指定类

如果我们希望按照自己的规则,来扫描包/子包下的某些注解, 可以通过 include-filter

(1)use-default-filters="false" 表示不使用默认的过滤机制/扫描机制(这个一定要有)
(2)context:include-filter 表示要去扫描哪些类
(3)type="annotation" 按照注解方式来扫描/过滤
(4)expression="org.springframework.stereotype.Service" 指定要扫描的注解的全路径

<context:component-scan base-package="com.spring.component" use-default-filters="false">
   <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
   <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
   <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>

 以上配置表示只扫描com.spring.component包下,带Service、Repository、Controller注解的类

  • 标记注解后,默认类名首字母小写作为 id 的值。也可以使用注解的 value 属性 指定 id 值,并且 value 可以省略。
@Controller(value="userAction01")

//value可以省略
@Controller("userAction01")

3.3 实现简单的 Spring 基于注解配置的程序

3.3.1 实现思路

3.3.2 代码实现

说明:以下实现代码基于上方入门案例中的四个类

(1)建注解ComponentScan.java,value属性代表扫描路径

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 ComponentScan {

    //表示ComponentScan注解可以传入一个value属性
    String value() default "";
}

(2)建WwjSpringConfig.java

/**
 * 这是一个配置类,作用类似于原生Spring的 beans.xml 容器配置文件
 */
@ComponentScan(value = "com.spring.component")
public class WwjSpringConfig {
}

(3)建WwjSpringApplicationCo ntext.java

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

import java.io.File;
import java.lang.annotation.Annotation;
import java.net.URL;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 该类作用类似于Spring原生ioc容器
 */
public class WwjSpringApplicationContext {
    //拿到配置类.class文件
    private Class configClass;
    //ioc存放的就是通过反射创建的对象
    private final ConcurrentHashMap<String,Object> ioc = new ConcurrentHashMap<>();

    //构造器
    public WwjSpringApplicationContext(Class configClass){
        this.configClass = configClass;
//        System.out.println("this.configClass=" + this.configClass);
        //获取要扫描的包
        //1.先获取到ComponentScan注解
        ComponentScan componentScan = (ComponentScan)this.configClass.getDeclaredAnnotation(ComponentScan.class);
        //2.获取到注解的value值
        String path = componentScan.value();
//        System.out.println("要扫描的包= " + path);

        //得到要扫描的包下的所有class文件(在target目录下)
        //1.得到类的加载器
        ClassLoader classLoader = WwjSpringApplicationContext.class.getClassLoader();
        //2.通过类的加载器获取到要扫描的包的资源路径
        path = path.replace(".","/");//一定要把.替换成/
        URL resource = classLoader.getResource(path);
//        System.out.println(resource);
        //3.将要加载的资源(.class) 路径下的文件进行遍历
        File file = new File(resource.getFile());
        if (file.isDirectory()){
            File[] files = file.listFiles();
            for (File f : files) {
//                System.out.println(f.getAbsolutePath());
                //获取到.class文件的绝对路径
                String fileAbsolutePath = f.getAbsolutePath();
                //这里只处理.class文件
                if (fileAbsolutePath.endsWith(".class")) {
                    //获取到类全类名
                    //1.获取到类名
                    String className = fileAbsolutePath.substring
                            (fileAbsolutePath.lastIndexOf("\\") + 1, fileAbsolutePath.indexOf(".class"));
//                System.out.println(className);
                    //2.拼接成全类名
                    String classFullName = path.replace("/",".") + "." + className;
//                    System.out.println(classFullName);
                    //3.判断该类是不是需要注入容器,看该类是不是有注解 @Component @Service @Repository @Controller
                    try {
                        //这时,就得到了该类的Class对象
                        //1. Class clazz = Class.forName(classFullName) 可以反射加载类
                        //2. classLoader.loadClass(classFullName); 也可以反射类的Class
                        //3. 区别是 : 上面方式会调用该类的静态方法, 下面方法不会
                        //4. aClass.isAnnotationPresent(Component.class) 判断该类是否有 @Component
                        Class<?> aClass = classLoader.loadClass(classFullName);
                        //判断该类是否有 @Component @Service @Repository @Controller
                        if (aClass.isAnnotationPresent(Component.class) ||
                                aClass.isAnnotationPresent(Service.class) ||
                                aClass.isAnnotationPresent(Repository.class) ||
                                aClass.isAnnotationPresent(Controller.class)){
                            //org.springframework.util.StringUtils包中的静态方法uncapitalize可以将字符串首字母小写
                            String keyVal = StringUtils.uncapitalize(className);
                            //获取到value值,替换指定id
                            if (aClass.isAnnotationPresent(Component.class)){
                                Component annotation = aClass.getDeclaredAnnotation(Component.class);
                                String value = annotation.value();
                                if (!value.equals("")){
                                    keyVal = value;
                                }
                            } else if (aClass.isAnnotationPresent(Service.class)) {
                                Service annotation = aClass.getDeclaredAnnotation(Service.class);
                                String value = annotation.value();
                                if (!value.equals("")){
                                    keyVal = value;
                                }
                            } else if (aClass.isAnnotationPresent(Repository.class)) {
                                Repository annotation = aClass.getDeclaredAnnotation(Repository.class);
                                String value = annotation.value();
                                if (!value.equals("")){
                                    keyVal = value;
                                }
                            } else if (aClass.isAnnotationPresent(Controller.class)) {
                                Controller annotation = aClass.getDeclaredAnnotation(Controller.class);
                                String value = annotation.value();
                                if (!value.equals("")){
                                    keyVal = value;
                                }
                            }

                            //这时候就可以创建该类的对象,并放入到ioc容器中
                            Class<?> clazz = Class.forName(classFullName);
                            Object o = clazz.newInstance();
//                            String defaultID = className.substring(0,1).toLowerCase() + className.substring(1);
//                            System.out.println(defaultID);
                            ioc.put(keyVal,o);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }

        }
    }

    public Object getBean(String id){
        return ioc.get(id);
    }
}

(4)创建测试主程序WwjSpringApplicationContextTest.java

public class WwjSpringApplicationContextTest {
    public static void main(String[] args) {
        WwjSpringApplicationContext ioc = new WwjSpringApplicationContext(WwjSpringConfig.class);
        System.out.println(ioc.getBean("yss1"));
        System.out.println(ioc.getBean("yss2"));
        System.out.println(ioc.getBean("yss3"));
    }

(5)运行结果

3.3.3 知识扩展:类加载器

java 的类加载器有 3 种

  • Bootstrap 类加载器:对应路径 jre/lib
  • Ext 类加载器:对应路径 jre/lib/ext
  • App 类加载器:对应路径 classpath
classpath 类路径,就是 java.exe 执行时,指定的路径,比如
D:\program\hspjdk8\bin\java.exe "-javaagent:D:\program\JavaIDEA2020.2\lib\idea_rt.jar=55992:D:\program\JavaIDEA 2020.2\bin" -Dfile.encoding=UTF-8 -classpathD:\program\hspjdk8\jre\lib\charsets.jar;D:\program\hspjdk8\jre\lib\deploy.jar;D:\program\hspjdk8\jre\lib\ext\access-bridge-64.jar;D:\program\hspjdk8\jre\lib\ext\cldrdata.jar;D:\program\hspjdk8\jre\lib\ext\dnsns.jar;D:\program\hspjdk8\jre\lib\ext\jaccess.jar;D:\program\hspjdk8\jre\lib\ext\jfxrt.jar;D:\program\hspjdk8\jre\lib\ext\localedata.jar;D:\program\hspjdk8\jre\lib\ext\nashorn.jar;D:\program\hspjdk8\jre\lib\ext\sunec.jar;D:\program\hspjdk8\jre\lib\ext\sunjce_provider.jar;D:\program\hspjdk8\jre\lib\ext\sunmscapi.jar;D:\program\hspjdk8\jre\lib\ext\sunpkcs11.jar;D:\program\hspjdk8\jre\lib\ext\zipfs.jar;D:\program\hspjdk8\jre\lib\javaws.jar;D:\program\hspjdk8\jre\lib\jce.jar;D:\program\hspjdk8\jre\lib\jfr.jar;D:\program\hspjdk8\jre\lib\jfxswt.jar;D:\program\hspjdk8\jre\lib\jsse.jar;D:\program\hspjdk8\jre\lib\management-agent.jar;D:\program\hspjdk8\jre\lib\plugin.jar;D:\program\hspjdk8\jre\lib\resources.jar;D:\program\hspjdk8\jre\lib\rt.jar; D:\java_projects\wwj-myspring\target\classes com.spring.AppMain

说明:classpath不是单个路径,而是一系列路径

3.4 自动装配

基于注解配置 bean,也可实现自动装配,使用的注解是:@AutoWired 或者 @Resource

3.4.1 @AutoWired 的规则说明

(1) IOC 容器中查找待装配的组件的 类型 ,如果有唯一的 bean 匹配,则使用该 bean
(2)如待装配的类型对应的 bean IOC 容器中有多个,则使用待装配的属性的属性名作
id 值再进行查找 , 找到就装配,找不到就抛异常

3.4.2 @Resource 的规则说明

(1)@Resource 有两个属性是比较重要的 , 分别是 name type,Spring @Resource 注解的
name 属性解析为 bean 的名字 , type 属性则解析为 bean 的类型 . 所以如果使用 name
, 则使用 byName 的自动注入策略 , 而使用 type 属性时则使用 byType 自动注入策略
比如@Resource(name = "userService") 表示装配 id=userService的对象
比如@Resource(type = UserService.class) 表示按照UserService.class类型进行装配, 这时要求容器中,只能有一个这样类型的对象
(2)如果 @Resource 没有指定 name type , 则先使用 byName(name的值为属性名) 注入策略 , 如果匹配不上 ,
再使用 byType 策略 , 如果都不成功,就会报错
说明: @Autowired + @Qualifier(value = "userService02") 组合也可以完成指定 name/id 来进行自动装配,这时,是装配的 id=userService02 , 需要两个注解都需要写上

3.4.3 应用案例

(1)实现 UserAction UserService 的两级自动组装

@Service
public class UserService {
    //方法..
    public void hi(){
        System.out.println("UserService hi()~");
    }
}
/**
 * @Controller 标识该类是一个控制器Controller, 通常这个类是一个Servlet
 */
@Controller
public class UserAction {
    //@Autowired 自动装配 UserService, 这时是以 UserService,class 类型对对象进行组装
    //如待装配的类型对应的 bean 在 IOC 容器中有多个,则是以 id=userService 的 UserService 对象进行组装
    @Autowired
    private UserService userService;

    public void sayOk() {
        System.out.println("UserAction 的sayOk()");
        System.out.println("userAction 装配的 userService属性=" + userService);
        userService.hi();
    }

    //不写这个方法,也可以完成组装
    public void setUserService(UserService userService) {
        this.userService = userService;
    }
}

(2)测试代码

@Test
public void setProByAnnotationAutowired() {
    ApplicationContext ioc = new ClassPathXmlApplicationContext("beans05.xml");
    UserAction userAction01 = ioc.getBean(UserAction.class);
    userAction01.sayOk();
}

3.5 泛型依赖注入

基本说明:

(1)为了更好的管理有继承和相互依赖的 bean 的自动装配,spring 还提供基于泛型依赖的注入机制

(2)在继承关系复杂情况下,泛型依赖注入就会有很大的优越性

应用实例:

(1)各个类关系图

(2)传统方法是将 PhoneDao /BookDao 自动装配到 BookService/PhoneSerive 中,当这种继承关系多时,就比较麻烦,可以使用 spring 提供的泛型依赖注入

(3)创建 Book.java,Phone.java等类

package com.spring.depinjection;
public class Book {
}

package com.spring.depinjection;

public class Phone {
}

package com.spring.depinjection;

public abstract class BaseDao<T> {
    public abstract void save();
}

package com.spring.depinjection;
import org.springframework.stereotype.Repository;

@Repository
public class BookDao extends BaseDao<Book> {
    @Override
    public void save() {
        System.out.println("BookDao 的 save()");
    }
}

package com.spring.depinjection;
import org.springframework.stereotype.Repository;

@Repository
public class PhoneDao extends BaseDao<Phone> {
    @Override
    public void save() {
        System.out.println("PhoneDao 的 save()");
    }
}

package com.spring.depinjection;
import org.springframework.beans.factory.annotation.Autowired;

public class BaseService<T> {
    @Autowired
    private BaseDao<T> baseDao;
    public void save() {
        baseDao.save();
    }
}

package com.spring.depinjection;
import org.springframework.stereotype.Service;

@Service
public class BookService extends BaseService<Book> {
}

package com.spring.depinjection;
import org.springframework.stereotype.Service;

@Service
public class PhoneService extends BaseService<Phone> {
}

 (4)修改 beans06.xml , 增加配置

<context:component-scan base-package="com.hspedu.spring.depinjection"/>

(5)测试代码

@Test
public void setProByDepinjectionAutowired() {
    ApplicationContext ioc = new ClassPathXmlApplicationContext("beans06.xml");
    BookService bookService = ioc.getBean(BookService.class);
    bookService.save();
    PhoneService phoneService = ioc.getBean(PhoneService.class);
    phoneService.save();
}

 (6)测试结果

  • 20
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第一课:面向抽象编程 4 第课:Jdom的基本使用 4 第三课:模拟Spring功能 5 第四课:搭建sping的运行环境 8 一、 建立一个新的项目 8 、 建立spring配置文件 8 三、 引入spring的jar包 8 四、 测试代码: 8 五、 注意接口的使用: 8 第五课:IOC(DI)配置及应用 9 一、 什么是IOC、DI 9 、 编辑xml文件时,没有提示 9 三、 注入类型(Injecting dependencies) 9 (一) setter注入类型Setter Injection 9 () 构造方法Constructor Injection 10 四、 id、name 11 五、 简单属性的注入 11 六、 Bean的作用范围scope 12 七、 集合注入 12 八、 自动装配autowire 13 (一) byName 13 () byType 14 (三) 注意 14 九、 生命周期 15 (一) lazy-init/default-lazy-init 15 () init-method destroy-method 不要和prototype一起用(了解) 15 第六课:annotation方式Spring 16 一、 开始使用annotation配置Spring 16 、 @Autowired、@Qualifier 16 (一) @Autowired 16 () @Qualifier 17 三、 @Resource(重要、推荐) 17 (一) JSR-250 17 () @Resource 17 四、 @Componet 18 五、 @Scope、@PostConstruct、@PreDestroy 19 六、 注解对应的jar包 19 第七课:AOP(面向切面编程) 19 一、 AOP概念 19 、 利用动态代理实现面向切面编程 20 第八课:Spring AOP配置选项 21 一、 AOP配置annotation方式 21 (一) 搭建annotation开发环境 21 () aspectJ类库 22 (三) AOP的annotation实例 22 (四) AspectJ的专业术语 23 (五) 织入点语法 23 (六) Advice 24 (七) Pointcut 26 (八) annotatin方式的AOP实例 26 、 AOP配置xml方式 27 三、 AOP实现动态代理注意 28 第九课:DataSource 28 一、 Sping配置数据源: 28 、 注入使用 29 三、 dbcp.BasicDataSource 29 第十课 Spring整合Hiberante3 30 一、 Spring配置hibernate3的SessionFactory 30 (一) xml形式的SessionFactory 30 () annotation注解方式的SessionFactory 30 、 引入hibernate所需要使用的jar 31 (一) 基本jar 31 () 加入annotation功能的jar包 31 (三) 搭建日志环境并配置显示DDL语句jar包 31 三、 Spring整合hibernate3事务 31 (一) Annotation注解方式配置事务管理 31 () Spring事务选项 35 (三) XML文件形式配置Spring事务管理 37 四、 HibernateTemplate 38 (一) HibernateTemplate 38 () HibernateDaoSupport 39 第十一课:Spring整合-SSH 40 一、 第一步:加入jar包(需要的jar包列表) 40 、 第步: 首先整合Spring + Hibernate 41 三、 第三步:再来整合Struts2 41 四、 struts的读常量: 43 第十课:DTO、VO 43 一、 DTO 43 、 VO 43 第十课:SSH整合存在的问题 43 一、 Jsp中访问Session时,Session已经关闭 43 、 如果不配置事务,openSessionView出现异常 44 三、 中文乱码问题: 44 第十三课:SSH整合的jar包 45 一、 Struts2 45 、 Hibernate3.3.2 45 三、 Spring 46
SpringIoc Spring的AOP , AspectJ Spring的事务管理 , 三大框架的整合 目录 1.1 Spring 框架学习路线:...........................................................................................................................4 1.2 Spring 框架的概述:...............................................................................................................................4 1.2.1 什么是 Spring:...........................................................................................................................4 1.2.2Spring 的核心:............................................................................................................................5 1.2.3Spring 的版本:............................................................................................................................5 1.2.4EJB:企业级 JavaBean.................................................................................................................5 1.2.5Spring 优点:.................................................................................................................................5 1.3 Spring 的入门的程序:...........................................................................................................................6 1.3.1 下载 Spring 的开发包:..............................................................................................................6 1.3.2 创建 web 工程引入相应 jar 包:................................................................................................7 1.3.3 创建 Spring配置文件:..........................................................................................................7 1.3.4 在配置配置类:.......................................................................................................................9 1.3.5 创建测试类:...............................................................................................................................9 1.3.6IOC 和 DI(*****)区别?..............................................................................................................9 1.3.7Spring 框架加载配置文件:......................................................................................................10 1.3.8BeanFactory 与ApplicationContext 区别?..............................................................................10 1.3.9MyEclipse 配置XML 提示:.....................................................................................................11 1.4 IOC 装配 Bean:....................................................................................................................................12 1.4.1Spring 框架Bean 实例化的方式:............................................................................................12 无参数构造方法的实例化:.......................................................................................................12 静态工厂实例化:.......................................................................................................................13 实例工厂实例化:.......................................................................................................................14 1.4.2Bean 标签的其他配置:.............................................................................................................15 id 和 name 的区别:....................................................................................................................15 类的作用范围:...........................................................................................................................15 Bean 的生命周期:......................................................................................................................18 1.4.3Bean 中属性注入:.....................................................................................................................23 构造器注入:...............................................................................................................................23 setter 方法注入:.........................................................................................................................24 setter 方法注入对象属性:.........................................................................................................25 名称空间 p:注入属性:...............................................................................................................25 SpEL:属性的注入(Spring 表达式):.....................................................................................25 1.4.4 集合属性的注入:.....................................................................................................................27 1.4.5 加载配置文件(文件的分离):.............................................................................................29 1.5 IOC 装配 Bean(注解方式)..................................................................................................................29 1.5.1Spring注解装配 Bean..........................................................................................................29 1.5.2Bean 的属性注入:.....................................................................................................................31 1.5.3Bean 其他的属性的配置:.........................................................................................................32 1.5.4Spring3.0 提供使用 Java 类定义 Bean 信息的方法(一般不用)......................................32 1.5.5 传统 XML注解的混合使用...............................................................................................34 1.5.6 实际开发中使用 XML 还是注解?.........................................................................................36 盲目的拾荒者2015-2016(泣血总结) 牛刚 第 2 页 共 119 页 1.6 Spring 整合web 开发:........................................................................................................................37 1.7 Spring 集成JUnit 测试:......................................................................................................................40 今天的内容总结:...............................................................................................................................................41 1.8 上次课的内容回顾:............................................................................................................................43 1.9 AOP 的概述:........................................................................................................................................43 1.9.1 什么是 AOP:............................................................................................................................43 1.9.2SpringAOP 思想........................................................................................................................44 1.9.3AOP 底层原理;.........................................................................................................................44 1.9.4Spring 的 AOP 代理:................................................................................................................44 1.9.5AOP 的术语:.............................................................................................................................44 1.10 AOP 的底层实现...............................................................................................................................45 1.10.1JDK 动态代理:........................................................................................................................45 1.10.2CGLIB 动态代理:...................................................................................................................48 1.10.3spring 代理知识总结:.............................................................................................................51 1.11 Spring 中的AOP...............................................................................................................................51 1.11.1Spring 的传统 AOP:..............................................................................................................51 1.11.2Spring 中的切面类型:............................................................................................................51 1.11.3Spring 的AOP 的开发:..........................................................................................................52 针对所有方法的增强:(不带有切点的切面)............................................................................52 带有切点的切面:(针对目标对象的某些方法进行增强)........................................................55 1.11.4 自动代理:...............................................................................................................................58 BeanNameAutoProxyCreator :按名称生成代理......................................................................59 DefaultAdvisorAutoProxyCreator :根据切面中定义的信息生成代理...................................60 1.12 Spring 的AspectJ 的 AOP(重点).....................................................................................................62 1.12.1 基于注解:...............................................................................................................................63 AspectJ 的通知类型:.................................................................................................................65 切点的定义:(真正那些方法增强).......................................................................................67 1.12.2 基于XML:.............................................................................................................................67 1.13 Spring 的JdbcTemplate....................................................................................................................70 1.13.1Spring 对持久层技术支持:....................................................................................................71 1.13.2 开发JDBCTemplate 入门:....................................................................................................71 1.13.3 配置连接池:...........................................................................................................................71 Spring 默认的连接池:...............................................................................................................71 DBCP 连接池:............................................................................................................................72 C3P0 连接池:.............................................................................................................................73 1.13.4 参数设置到属性文件中:.......................................................................................................74 1.13.5JdbcTemplate 的 CRUD 的操作:(学会用手册)....................................................................75 今天的内容总结:...............................................................................................................................................83 今日内容....................................................................................................................................................85 上次课的内容回顾:...................................................................................................................................85 1.14 Spring 的事务管理:...........................................................................................................................87 1.14.1 事务:.......................................................................................................................................87 Spring 学习笔记 2015-2016(泣血总结) 牛刚 第 3 页 共 119 页 1.14.2Spring 中事务管理:................................................................................................................87 Spring 提供事务管理API:........................................................................................................87 1.14.3Spring 的事务管理:................................................................................................................89 1.14.4 事务操作的环境搭建:...........................................................................................................89 1.14.5Spring 的事务管理:................................................................................................................94 手动编码的方式完成事务管理:...............................................................................................94 声明式事务管理:(原始方式)....................................................................................................95 声明式事务管理:(自动代理.基于切面**重点掌握 ssh 整合用的就是这个**,基于 tx/aop)97 基于注解的事务管理:...............................................................................................................99 1.15 SSH 框架整合:................................................................................................................................100 1.15.1Struts2+Spring+Hibernate 导包............................................................................................100 1.15.2Struts2 和 Spring 的整合:.....................................................................................................104 1.15.3Struts2 和 Spring 的整合两种方式:.....................................................................................106 Struts2 自己管理 Action:(方式一)..........................................................................................106 Action 交给 Spring 管理:(方式)..........................................................................................106 Web 层获得 Service:...............................................................................................................107 1.15.4Spring 整合Hibernate:..........................................................................................................110 零障碍整合:(一)......................................................................................................................110 没有 Hibernate 配置文件的形式().....................................................................................112 1.15.5HibernateTemplate 的API:...................................................................................................113 1.15.6OpenSessionInView:.............................................................................................................115 1.16 基于注解的方式整合 SSH:...........................................................................................................115
第一课:面向抽象编程 4 第课:Jdom的基本使用 4 第三课:模拟Spring功能 5 第四课:搭建sping的运行环境 8 一、 建立一个新的项目 8 、 建立spring配置文件 8 三、 引入spring的jar包 8 四、 测试代码: 8 五、 注意接口的使用: 8 第五课:IOC(DI)配置及应用 9 一、 什么是IOC、DI 9 、 编辑xml文件时,没有提示 9 三、 注入类型(Injecting dependencies) 9 (一) setter注入类型Setter Injection 9 () 构造方法Constructor Injection 10 四、 id、name 11 五、 简单属性的注入 11 六、 Bean的作用范围scope 12 七、 集合注入 12 八、 自动装配autowire 13 (一) byName 13 () byType 14 (三) 注意 14 九、 生命周期 15 (一) lazy-init/default-lazy-init 15 () init-method destroy-method 不要和prototype一起用(了解) 15 第六课:annotation方式Spring 16 一、 开始使用annotation配置Spring 16 、 @Autowired、@Qualifier 16 (一) @Autowired 16 () @Qualifier 17 三、 @Resource(重要、推荐) 17 (一) JSR-250 17 () @Resource 17 四、 @Componet 18 五、 @Scope、@PostConstruct、@PreDestroy 19 六、 注解对应的jar包 19 第七课:AOP(面向切面编程) 19 一、 AOP概念 19 、 利用动态代理实现面向切面编程 20 第八课:Spring AOP配置选项 21 一、 AOP配置annotation方式 21 (一) 搭建annotation开发环境 21 () aspectJ类库 22 (三) AOP的annotation实例 22 (四) AspectJ的专业术语 23 (五) 织入点语法 23 (六) Advice 24 (七) Pointcut 26 (八) annotatin方式的AOP实例 26 、 AOP配置xml方式 27 三、 AOP实现动态代理注意 28 第九课:DataSource 28 一、 Sping配置数据源: 28 、 注入使用 29 三、 dbcp.BasicDataSource 29 第十课 Spring整合Hiberante3 30 一、 Spring配置hibernate3的SessionFactory 30 (一) xml形式的SessionFactory 30 () annotation注解方式的SessionFactory 30 、 引入hibernate所需要使用的jar 31 (一) 基本jar 31 () 加入annotation功能的jar包 31 (三) 搭建日志环境并配置显示DDL语句jar包 31 三、 Spring整合hibernate3事务 31 (一) Annotation注解方式配置事务管理 31 () Spring事务选项 35 (三) XML文件形式配置Spring事务管理 37 四、 HibernateTemplate 38 (一) HibernateTemplate 38 () HibernateDaoSupport 39 第十一课:Spring整合-SSH 40 一、 第一步:加入jar包(需要的jar包列表) 40 、 第步: 首先整合Spring + Hibernate 41 三、 第三步:再来整合Struts2 41 四、 struts的读常量: 43 第十课:DTO、VO 43 一、 DTO 43 、 VO 43 第十课:SSH整合存在的问题 43 一、 Jsp中访问Session时,Session已经关闭 43 、 如果不配置事务,openSessionView出现异常 44 三、 中文乱码问题: 44 第十三课:SSH整合的jar包 45 一、 Struts2 45 、 Hibernate3.3.2 45 三、 Spring 46
1、Spring配置文件 Spring配置文件是Spring框架中非常重要的一部分,它通常以XML格式编写,用于配置Spring应用程序中的各种组件,例如Bean、AOP、数据源、事务等。 在Spring配置文件中,最常用的标签是<bean>标签,用于定义和配置Spring IoC容器中的Bean对象。除此之外,还有<import>标签,用于引入其他配置文件;<aop:config>标签,用于配置AOP相关的切面和通知等;<tx:advice>标签,用于配置事务管理相关的通知等。 Spring配置文件的编写需要遵守一定的规范和约束条件,例如必须指定命名空间、必须定义命名空间的schema等。同时,Spring还提供了多种加载配置文件的方式,例如ClassPathXmlApplicationContext、FileSystemXmlApplicationContext等。 2、Spring IoC基于注解的操作和案例 除了使用XML配置文件之外,Spring IoC容器还支持基于注解Bean定义和注入操作。在Spring中,使用注解可以大大简化配置文件的编写,提高开发效率和可读性。 常用的Spring注解包括: - @Component:用于标识一个组件,通常与@Autowired等注解一起使用。 - @Autowired:用于自动注入一个Bean对象。 - @Qualifier:用于指定一个Bean对象的名称。 - @Value:用于注入一个基本类型或String类型的属性值。 - @Configuration:用于标识一个配置类,通常与@Bean等注解一起使用。 - @Bean:用于定义一个Bean对象,通常用于@Configuration类中。 - @Profile:用于指定一个Bean对象的环境依赖。 下面是一个基于注解Spring IoC配置案例: ``` @Configuration public class AppConfig { @Bean public UserService userService() { return new UserServiceImpl(); } } ``` 在这个案例中,使用@Configuration注解表示这是一个配置类,使用@Bean注解表示定义了一个名为“userService”的Bean对象。该Bean对象的类型是UserServiceImpl。 另外,还可以使用@Autowired和@Qualifier注解来实现Bean的自动注入。例如: ``` @Service public class UserServiceImpl implements UserService { @Autowired @Qualifier("userRepository") private UserRepository userRepository; // ... } ``` 在这个案例中,使用@Service注解表示这是一个服务类,使用@Autowired注解表示自动注入一个名为“userRepository”的Bean对象。其中,@Qualifier注解用于指定Bean对象的名称。 总之,Spring配置文件和基于注解的操作是Spring框架中非常重要和常用的组件,它们为Java开发人员提供了一种高效、灵活和可维护的方式来管理对象和依赖关系。通过基于注解的方式,可以大大简化配置文件的编写工作,提高开发效率和可读性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值