Spring框架学习(一)——bean的理解与搭建

一、Spring概述

  1. Spring是一个开源框架
  2. Spring为简化企业级开发而生,使用Spring,JavaBean就可以实现很多以前要靠EJB才能实现的功能。同样的功能,在EJB中要通过繁琐的配置和复杂的代码才能够实现,而在Spring中却非常的优雅和简洁。
  3. Spring是一个IOC(DI)和AOP容器框架。
  4. Spring的优良特性
    ① 非侵入式:基于Spring开发的应用中的对象可以不依赖于Spring的API
    ② 依赖注入:DI——Dependency Injection,反转控制(IOC)最经典的实现。
    ③ 面向切面编程:Aspect Oriented Programming——AOP
    ④ 容器:Spring是一个容器,因为它包含并且管理应用对象的生命周期
    ⑤ 组件化:Spring实现了使用简单的组件配置组合成一个复杂的应用。在 Spring 中可以使用XML和Java注解组合这些对象。
  5. 一站式:在IOC和AOP的基础上可以整合各种企业应用的开源框架和优秀的第三方类库(实际上Spring 自身也提供了表述层的SpringMVC和持久层的Spring JDBC)。
  6. Spring模块
    在这里插入图片描述

二、入门案例

1.搭建一个idea的spring环境

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
spring-config.xml为spring 的配置文件

2.Helloword

<1>正常创建一个Helloworld.java

指明一个私有变量,并且创建get set方法,和实现变量的一个输出方法

public class Helloworld {
    private String helloworld;

    public String gethelloworld() {

        return helloworld;
    }

    public void sethelloworld(String helloworld) {
        this.helloworld = helloworld;
    }

    public void sayhelloworld(){
        System.out.println(helloworld);
    }
}
<2>创建一个main方法,利用spring 的IOC容器获取对象来实现输出
 public static void main(String[] args) {
        //获取到helloworld对象。

        //1.创建spring的IOC容器对象
        ApplicationContext ctx=new ClassPathXmlApplicationContext("spring-config.xml");
        //2.获取helloworld,getBean(id)因为是从IOC中获取到的对象配置,所以需要强制转换回来
        Helloworld helloworld = (Helloworld) ctx.getBean("hello");
        //3.调用方法
        helloworld.sayhelloworld();
        /**
         * 从spring的配置文件里,将创建的已有get set方法的变量进行name,value的直接针对性的赋值
         * 减少new的调用
         */
    }

最后附上配置文件和输出

<?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="hello" class="test.Helloworld" >
            <property name="helloworld" value="Helloworld!!!"></property>
        </bean>
</beans>

在这里插入图片描述
注:

(1)IOC(反转控制)

通过容器主动将资源推送给需要的组件,这样在开发的时候就可以 只需要接收资源即可,提高效率。

(2)DI(依赖注入)

组件以预先定义好的方式(get set)接收来自容器的资源注入。

(3)通过类型获取bean

1.从IOC容器中获取ean的时候,除了可以通过id值获取到,还可以通过bean的类型获取,但是同一个class内,声明了多个相同名称的对象就会报错

Helloworld helloworld = ctx.getBean(Helloworld.class);

2.但是也可以同时声明id和和类名

Helloworld helloworld = ctx.getBean("helloworld", Helloworld.class);

具体配置方法如下:

<!--配置方法:
            基于xml,使用全类名
            <bean>:受spring管理的一个javaBean对象
                id:<bean>的唯一标识。在整个IOC容器中唯一且不重复
                class:制定javaBean的全类名。目的是通过反射创建对象
                Class cls = Class.forName("test.Helloworld");
                Object obj = cls.newInstance();
                这里因为使用了newInstance所以创建无参构造器,因为newInstance默认调用无参构造器
            <property>:给对象的属性赋值
                name:指定属性名,属性名不是创建的私有成员变量,而是set方法所设置的变量
                value:指定属性值
         -->

3.IOC在Spring中的实现

(1)读取IOC的bean之前需要先将IOC容器本身进行实例化
(2)两种IOC的实现方式:
1.BeanFactory:面向Spring本身,开发人员不可用
2.ApplicationContext:BeanFactory的子接口,提供了更多的高级特性,使用的时候直接使用这个而不是底层的BeanFactory

4.给普通bean的属性进行赋值

<1>通过set方法注入
<!--DI依赖注入的方法:set方法注入
        根据set什么而决定property的各方面属性
        而通过IOC容器进行属性选取的时候,会自动调用该方法的set函数
    -->
        <bean id="car" class="DI.Car">
            <property name="brand" value="奥迪"></property>
            <property name="crop" value="一汽"></property>
            <property name="price" value="400000"></property>
        </bean>
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-config.xml");
        Car car = ctx.getBean("car",Car.class);
        System.out.println(car.toString());
        //output:Car{brand='宝马', crop='华晨', price=450000.0}
<2>通过bean的构造器进行赋值

1.Spring自动匹配合适的构造器

<!--DI依赖注入的方法:构造器注入
        根据有参构造器的顺序直接进行赋值
    -->
    <bean id="car1" class="DI.Car">
        <constructor-arg value="宝马"></constructor-arg>
        <constructor-arg value="华晨"></constructor-arg>
        <constructor-arg value="450000"></constructor-arg>
    </bean>
public Car(String brand, String crop, Double price) {
        this.brand = brand;
        this.crop = crop;
        this.price = price;
    }

2.通过构造器索引赋值

<bean id="car1" class="DI.Car">
        <constructor-arg value="宝马" index="0"/>
        <constructor-arg value="华晨" index="1"/>
        <constructor-arg value="450000" index="2"/>
    </bean>

注:
1.当同时有多构造器的时候在参数种类相同的时候优先匹配最后定义的构造器
这样就会产生一个问题,会让我们匹配到不想匹配的构造器,此时应该多声明一个type

<bean id="car1" class="DI.Car">
        <constructor-arg value="宝马" index="0" type="java.lang.String"/>
        <constructor-arg value="华晨" index="1" type="java.lang.String"/>
        <constructor-arg value="450000" index="2" type="java.lang.Double"/>
    </bean>
<3>p命名空间
<!--
        使用p命名空间,底层其实还是set,所以没有set方法的参数无法使用这个p
    -->
<bean id="car2" class="DI.Car"
          p:brand="福特"
          p:crop="长安"
          p:price="300000"/>
<4>字面量
<!--    字面量
        特殊字符:
            1.使用实体:
                &:&amp
                <:&lt
                >:&gt
                ":&quot

            2.<![CDATA[写任意字符]]>
    -->
    <bean id="book" class="DI.Book">
        <property name="bookName">
            <value> <![CDATA[<<大冒险家>>]]> </value>
        </property>
    </bean>
public class Book {
    private Integer bookId;
    private String bookName;

    public Integer getBookId() {
        return bookId;
    }

    public void setBookId(Integer bookId) {
        this.bookId = bookId;
    }

    public String getBookName() {
        return bookName;
    }

    public void setBookName(String bookName) {
        this.bookName = bookName;
    }

    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-config.xml");
        Book book = ctx.getBean("book",Book.class);
        System.out.println(book.bookName);
    }
}
<5>引用其他的bean

1.当我们想要在类中创建一个私有对象的时候,在spring-config的配置文件中,需要的是初始化一个对象,这时就要借助其他声明过了的对象实例,要在name后声明ref,并且指向想要调用的目标类。
注意:
只可引用IOC容器内部的对象实例。
在这里插入图片描述

<6>内部bean

使用内部bean是因为之前没有可以使用的现成的bean,所以要在引用私有对象的时候重新对该bean进行编写,但是必须得保证有这个类。

<!--
        引用一个内部bean
        应用场景:想要在IOC声明一个对象实例,但是没有可以直接使用的bean
        就会使用内部bean进行补充说明

    -->
    <bean id="person1" class="DI.Person">
        <property name="id" value="101"/>
        <property name="name" value="bentia"
        <property name="car" >
            <bean class="DI.Car">
                <property name="brand" value="Mini"></property>
                <property name="crop" value="baoma"></property>
                <property name="price" value="4500000"></property>

            </bean>
        </property>
    </bean>
<7>在bean中给属性赋空值
    <!--
        给属性赋一个null值
    -->
    <bean id="person2" class="DI.Person">
        <property name="id" value="100"/>
        <property name="name" value="zhangzhang"/>
        <property name="car"><null/></property>
    </bean>
public class Person {
    private Integer id;
    private String name;
    private Car car;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public Car getCar() {
        return car;
    }

    public void setCar(Car car) {
        this.car = car;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", car=" + car +
                '}';
    }

    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-config.xml");
        Person person = ctx.getBean("person2", Person.class);
        System.out.println(person.toString());
    }
}//output:Person{id=100, name='zhangzhang', car=null}
<8>在bean中添加list属性值

条件:在类中声明了list类,包含之前已经创建的类的对象们。

<!--
        List集合
    -->
    <bean id="list" class="collection.list">
        <property name="name" value="zhangzhang"></property>
        <property name="cars">
            <list>
                <ref bean="car1"></ref>
                <ref bean="car"></ref>
                <ref bean="car2"></ref>
            </list>
        </property>
    </bean>
public class list {
    private String name;
    private List<Car> cars;

    public String getName() {
        return name;
    }

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

    public List<Car> getCars() {
        return cars;
    }

    public void setCars(List<Car> cars) {
        this.cars = cars;
    }

    @Override
    public String toString() {
        return "list{" +
                "name='" + name + '\'' +
                ", cars=" + cars +
                '}';
    }

    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-config.xml");
        list list = ctx.getBean("list", list.class);
        System.out.println(list.toString());
    }//output:list{name='zhangzhang', cars=[Car{brand='奥迪', crop='一汽', price=400000.0}, Car{brand='宝马', crop='华晨', price=450000.0}, Car{brand='福特', crop='长安', price=300000.0}]}

注:
1.如果ref引用的对象在之前的其他bean内被ref过且修改过引用值,那么再ref的话,就会直接变成上次修改过后的值引用过来。
2.在这里可以把所有的list换成Array,IOC内也封装好了<array>的标签,但是推荐用list,因为list既可以当array用,也可以当list用

<9>在bean中添加Map属性值
<!--
        Map集合
    -->
    <bean id="personMap" class="collection.map">
        <property name="name" value="OP"></property>
        <property name="map">
            <map>
                <entry key="AA" value-ref="car"></entry>
                <entry key="BB" value-ref="car1"></entry>
                <entry key="CC" value-ref="car2"></entry>
            </map>
        </property>
    </bean>
public class map {
    private String name;
    private Map<String, Car> map;

    public String getName() {
        return name;
    }

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

    public Map<String, Car> getMap() {
        return map;
    }

    public void setMap(Map<String, Car> map) {
        this.map = map;
    }

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

    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-config.xml");
        collection.map map = ctx.getBean("personMap", map.class);
        System.out.println(map.toString());
    }
}//output:map{name='OP', map={AA=Car{brand='奥迪', crop='一汽', price=400000.0}, BB=Car{brand='宝马', crop='华晨', price=450000.0}, CC=Car{brand='福特', crop='长安', price=300000.0}}}
<10>集合类型的bean
<util:list id="listbean">
        <ref bean="car"></ref>
        <ref bean="car1"></ref>
        <ref bean="car2"></ref>
    </util:list>

由于我们这里给bean打了一个包成为了一个新的listbean,所以,我们也可以在外界使用list集合的时候直接去调用这个打包好的listbean,比如:

<!--
        List集合
    -->
    <bean id="list" class="collection.list">
        <property name="name" value="zhangzhang"></property>
        <property name="cars" ref="listbean">
            <!--直接实现bean的调用-->
            <!--<list>-->
                <!--<ref bean="car1"></ref>-->
                <!--<ref bean="car"></ref>-->
                <!--<ref bean="car2"></ref>-->
            <!--</list>-->
        </property>
    </bean>

5.给工厂bean的属性进行赋值

简述:在Spring中有两种类型的bean,一种是普通bean,另一种是工厂bean,即FactoryBean。

工厂bean跟普通bean不同,其返回的是该工厂bean的getObject方法所返回的对象。
工厂bean必须实现org.springframework.beans.factory.FactoryBean接口

/**
 * 用泛型创建一个car对象
 */
public class carFactoryBean implements FactoryBean<Car> {
    /**
     * 工厂bean具体创建的bean对象是由getObject方法来返回的。
     * @return
     * @throws Exception
     */
    @Override
    public Car getObject() throws Exception {
        return new Car("五菱宏光","五菱",40000.0);
    }

    /**
     * 返回具体的bean对象的类型也就是Car.class
     * @return
     */
    @Override
    public Class<?> getObjectType() {
        return Car.class;
    }

    /**
     * 判断bean是否是单例的
     * 讲bean的作用域的时候再深究
     * @return
     */
    @Override
    public boolean isSingleton() {
        return false;
    }

    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-factory.xml");
        Car car = ctx.getBean("car", Car.class);
        System.out.println(car.toString());
    }
}//output:Car{brand='五菱宏光', crop='五菱', price=40000.0}

spring-factory.xml配置如下

<bean id="car" class="FactoryBean.carFactoryBean"></bean>

当调用IOC的时候系统自动就从id获取到此类bean为一个工厂bean,因为继承了BeanFactory的接口
工厂bean的意义在于,之前的普通bean在创建的时候,都是通过配置文件来创建,而工厂bean的意义在于可以通过getObject方法自己手动通过一系列算法创建一个bean对象了,单纯spring用的不多,都是在整合的时候用的多

6.bean的高级配置

<1>bean的继承
<!--
        Bean的继承关系
    -->
    <bean id="address1" class="relation.address">
        <property name="city" value="河南"></property>
        <property name="street" value="河南路"></property>
    </bean>
    <bean id="address2" parent="address1">
        <property name="city" value="北京"></property>
    </bean>
public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-config.xml");
        address address1 = ctx.getBean("address1", address.class);
        address address2 = ctx.getBean("address2", address.class);
        System.out.println(address1.toString());
        System.out.println(address2.toString());
    }//output:address{city='北京', street='河南路'}

也可以在bean标签内注明bean的抽象属性,如果abstract="true"则bean无法被实例化

<bean id="address1" class="relation.address" abstract="true">
        <property name="city" value="河南"></property>
        <property name="street" value="河南路"></property>
    </bean>
    <bean id="address2" parent="address1">
        <property name="city" value="北京"></property>
    </bean>

Bean的继承关系,当创建一个抽象bean的时候就无法在类中正常的进行实例化了,但是子类不受影响,和javase一样
继承可以获取父类bean的正常配置,但是id abstract autowire是不能被继承的

<2>bean之间的依赖关系
    <!--
        bean的依赖关系
        说是依赖关系,但是更像是前提条件
    -->
    <bean id="address3" class="relation.address" parent="address1" depends-on="adress4"/>

    <bean id="address4" class="relation.address"/>

在这里address4就是address3的前提条件,如果depend-on 的bean id不存在也就无法对此bean进行实例化。

7.bean的作用域

    <!--
        bean的作用域:
        singleton:同单例模式一样,当一个bean被scope="singleton"修饰的时候,实例化多少次都是相同的对象
        prototype:原型模式,可以实例化多次,且每次对象不同
        request:一次请求对应一个bean对象
        Session:一次会话对应一个bean对象
    -->
    <bean id="carScope" class="relation.carScope" scope="singleton">
        <property name="brand" value="小汽车"></property>
        <property name="price" value="540000"></property>
    </bean>
public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-config.xml");
        carScope carScope1 = ctx.getBean("carScope", carScope.class);
        carScope carScope2 = ctx.getBean("carScope", carScope.class);
        System.out.println(carScope1==carScope2);
    }
    //output:true

8.bean的生命周期

  • 第一阶段:调用了构造器
  • 第二阶段:properties自动运行的set
  • 第三阶段:调用初始化方法
  • 第四阶段:使用bean对象
  • 第五阶段:销毁
    <!--
        Bean的生命周期
    -->
    <bean id="carlife" class="lifestyle.carLifeStyle" init-method="init" destroy-method="destroy">
        <property name="brand" value="宝马"></property>
        <property name="price" value="54000"></property>
    </bean>
public class carLifeStyle {
    private String brand;
    private Double price;

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public Double getPrice() {

        return price;
    }

    /**
     * bean的初始化
     * 通过init-method来指定初始化方法
     */
    public void init(){
        System.out.println("第三阶段:调用初始化方法");
    }

    /**
     * bean的销毁:IOC容器关闭,bean容器关闭
     */
    public void destroy(){
        System.out.println("第五阶段:销毁");
    }

    public void setPrice(Double price) {
        System.out.println("第二阶段:properties自动运行的set");
        this.price = price;
    }

    public carLifeStyle() {
        System.out.println("第一阶段:调用了构造器");
    }

    @Override
    public String toString() {
        return "carLifeStyle{" +
                "brand='" + brand + '\'' +
                ", price=" + price +
                '}';
    }

    public static void main(String[] args) {
        ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext("spring-config.xml");
        carLifeStyle carLifeStyle = ctx.getBean("carlife", lifestyle.carLifeStyle.class);
        System.out.println("第四阶段:使用bean对象:"+carLifeStyle.toString());

//        关闭IOC容器
        ctx.close();
    }
}
/**output:
 * 第一阶段:调用了构造器
 * 第二阶段:properties自动运行的set
 * 第三阶段:调用初始化方法
 * 第四阶段:使用bean对象:carLifeStyle{brand='宝马', price=54000.0}
 * 第五阶段:销毁
 * 一月 18, 2019 9:24:04 下午 org.springframework.context.support.ClassPathXmlApplicationContext doClose
 * 信息: Closing org.springframework.context.support.ClassPathXmlApplicationContext@27fa135a: startup date [Fri Jan 18 21:24:04 CST 2019]; root of context hierarchy
 */
  • bean的后置处理器
    是针对bean的生命周期中的特定操作
/**
 * Bean的后置处理器,对IOC容器内的所有Bean都产生作用
 */
public class myBeanPostProcessior implements BeanPostProcessor {
    /**
     * 在bean初始化之前的行文
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     *
     * Object bean:正在被创建的bean对象
     * String beanName:bean对象的id值
     *
     * 在生命周期第二步到第三步之间执行:由于在这里对bean直接进行了操作,所以要返回一个bean
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization");
        return bean;
    }

    /**
     * 在Bean初始化之后的行为
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     *
     * 在生命周期第三步到第四步之间执行
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization");
        return bean;
    }
}
/**output:
 * 第一阶段:调用了构造器
 * 第二阶段:properties自动运行的set
 * postProcessBeforeInitialization
 * 第三阶段:调用初始化方法
 * postProcessAfterInitialization
 * 第四阶段:使用bean对象:carLifeStyle{brand='宝马', price=54000.0}
 * 第五阶段:销毁
 */
    <!--
        配置后置处理器
    -->
    <bean class="lifestyle.myBeanPostProcessior"></bean>

9.自动装配

手动装配:之前学习过程中所使用到的全部都是手动装配,即通过value ref 方式明确指定属性值都是手动装配。
自动装配:根据指定的装配规则,不需要明确指定,spring将自动匹配的属性值注入bean中。

    <!--CarAuto-->
    <bean id="car" class="autowire.CarAuto">
        <property name="brand" value="奔驰"></property>
        <property name="price" value="540000"></property>
    </bean>
    <!--AddressAuto-->
    <bean id="address" class="autowire.AddressAuto">
        <property name="province" value="天津"></property>
        <property name="city" value="天津河西"></property>
    </bean>
    <!--PersonAuto:自动装配
    byName:用想要匹配的bean的id和想要匹配的对象的实例名比较。匹配成功则装配成功。
    byType:用想要匹配的bean的class和其他的bean的class进行对比,匹配成功则装配成功但是如果匹配了两个相同的class出来就会报错
    -->
    <bean id="person" class="autowire.PersonAuto" autowire="byType">
        <property name="name" value="zz"></property>
    </bean>

用PersonAuto去自动装配CarAuto和AddressAuto的对象,也是要把get set方法写全,因为还是用的property去匹配,所以要把set的值写对了。

//CarAuto建立的私有属性
private String brand;
private Double price;
//AddressAuto建立的私有属性
private String province;
private String city;
//PersonAuto建立的私有属性
/**
* 可以自动装配的只有引用类型和对象类型
*/
private String name;//必须手动装配
private CarAuto car;//可以进行自动装配
private AddressAuto address;//可以进行自动装配

测试类

public class test {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-autowire.xml");
        PersonAuto personAuto = ctx.getBean("person", PersonAuto.class);
        System.out.println(personAuto.toString());
    }
}
//output:PersonAuto{name='zz', carAuto=CarAuto{brand='奔驰', price=540000.0}, addressAuto=AddressAuto{province='天津', city='天津河西'}}

10.基于注解配置bean

相对于配置xml而言,使用注解去配置bean更加简洁和优雅,并且和MVC对接的时候十分契合,是开发中常用的设计理念。

<1>常用注解

普通组件:@Component
标识一个受SpringIOC容器管理的组件

持久化层组件:@Repository
标识一个受SpringIOC容器管理的持久化层组件

业务逻辑层组件:@Service
标识一个受SpringIOC容器管理的业务逻辑层组件

持久化层组件:@Controller
标识一个受SpringIOC容器管理的表述层控制器组件
在这里插入图片描述

<2>扫描组件
<!--
        组件扫描:扫描加了注解的类,并且管理到IOC容器中
        base-package:基包.Spring会扫描指定包以及子包下所有的类,将带有注解的类管理到IOC容器中
   -->
    <context:component-scan base-package="annotation"/>

controller层

/**
 * 加了注解的作用:
 * 相当于在xml配置文件中自动配置了:
 * <bean id="userController" class="annotation.controller.UserController"></bean>
 *
 * 注解默认的id值就是类名的首字母小写,也可以在类名中手动指定id值:@Controller(value = "id值")也可以简写为:@Controller("id值")
 */
@Controller
public class UserController {
    
}

service层

@Service
public class UserServiceImpl {
}

dao层

@Repository
public class UserDAOJdbcImpl implements UserDAO{
}

测试方法

public class testAnnotation {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-annotation.xml");
        UserController uc = ctx.getBean("userController", UserController.class);
        System.out.println("UserController:"+uc);

        UserServiceImpl us = ctx.getBean("userServiceImpl", UserServiceImpl.class);
        System.out.println("UserServiceImpl:"+us);

        UserDAOJdbcImpl ud = ctx.getBean("userDAOJdbcImpl", UserDAOJdbcImpl.class);
        System.out.println("UserDAOJdbcImpl:"+ud);
    }
}
/**output:
 * UserController:annotation.controller.UserController@18bf3d14
 * UserServiceImpl:annotation.service.UserServiceImpl@4fb64261
 * UserDAOJdbcImpl:annotation.dao.UserDAOJdbcImpl@42607a4f
 */
<3>指定扫描

指定只对controller进行扫描

  • 第一种方法:
    在type内写上annotation,expression后面跟着import导进来的
    import org.springframework.stereotype.Controller;
    并且必须指定use-default-filters=“false”
    这样便可以令IOC容器只对annotation包下的UserController类进行扫描
<context:component-scan base-package="annotation" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"></context:include-filter>
    </context:component-scan>
  • 第二种方法:
    type那里写assignable,后面expression写全类名,也可以达到同样的效果
<context:component-scan base-package="annotation" use-default-filters="false">
        <context:include-filter type="assignable" expression="annotation.controller.UserController"></context:include-filter>
    </context:component-scan>
<3>排除扫描

排除controller进行其他所有的扫描

  • 第一种方法:
    在type内写上annotation,expression后面跟着import导进来的
    import org.springframework.stereotype.Controller;
    并且必须指定use-default-filters="true"也可以不写,因为默认就是true
    这样便可以令IOC容器排除annotation包下的UserController类进行扫描
<context:component-scan base-package="annotation" use-default-filters="true">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"></context:exclude-filter>
    </context:component-scan>
  • 第二种方法:
    type那里写assignable,后面expression写全类名,也可以达到同样的效果
    <context:component-scan base-package="annotation" use-default-filters="true">
        <context:exclude-filter type="assignable" expression="annotation.controller.UserController"/>
    </context:component-scan>
<4>组件装配

controller

@Controller
public class UserController {
    @Autowired
    private UserService userService;//之所以不直接调用实现的Service的类是因为会耦合,并且为了防止业务修改,所以用一个不会变的借口最稳妥

    public void regist(){
        userService.handleAddUser();
    }
}

service

@Service
public class UserServiceImpl implements UserService{

    /**
     * @Autowired 完成bean属性的自动装配
     *
     * 工作机制:首先会使用byType自动装配,如果能唯一匹配就会装配成功,
     * 如果不能唯一匹配,就会使用byName来确定唯一,如果还不行就会抛异常
     *
     * 默认情况下,使用@Autowired标注的属性必须被装配,如果装配不了,也会抛出异常
     * 可以使用required=false来设置不是必须被装配,但如果不装配,就会报空指针异常
     *
     * 在byType进行匹配的时候有多个都满足条件,则可以通过@qualifier来指定id
     * 
	 * @Qualifier和@Autowire 既可以直接加在私有对象上,也可以加在对象的set方法上
     */
    @Autowired(required = false)
    @Qualifier("userDAOJdbcImpl")
    private UserDAO userDAO;

    @Override
    public void handleAddUser() {
//        处理业务
        userDAO.addUser();
    }
}

dao

@Repository
public class UserDAOJdbcImpl implements UserDAO{
    @Override
    public void addUser() {
        System.out.println("addUser");
    }
}

test

public class testAnnotation {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-annotation.xml");
        UserController uc = ctx.getBean("userController", UserController.class);
//        System.out.println("UserController:"+uc);

        UserServiceImpl us = ctx.getBean("userServiceImpl", UserServiceImpl.class);
//        System.out.println("UserServiceImpl:"+us);

        UserDAOJdbcImpl ud = ctx.getBean("userDAOJdbcImpl", UserDAOJdbcImpl.class);
//        System.out.println("UserDAOJdbcImpl:"+ud);

        uc.regist();
    }
}
//output:addUser

猜你喜欢

转载自blog.csdn.net/qq_41936805/article/details/86417505