1. 声明Bean的注解  72

负责声明Bean的注解,常见的包括四个:

● @Component

● @Controller

● @Service

● @Repository

1.1 源码如下:

1.1.1 @Component注解

package com.powernode.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(value = {ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
public @interface Component {
    String value();
}

1.1.2 @Controller注解

package org.springframework.stereotype;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
    @AliasFor(
        annotation = Component.class
    )
    String value() default "";
}

1.1.3 @Service注解

package org.springframework.stereotype;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {
    @AliasFor(
        annotation = Component.class
    )
    String value() default "";
}

1.1.4 @Repository注解

package org.springframework.stereotype;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Repository {
    @AliasFor(
        annotation = Component.class
    )
    String value() default "";
}

1.2 通过源码可以看到

@Controller、@Service、@Repository这三个注解都是@Component注解的别名。

也就是说:这四个注解的功能都一样。用哪个都可以。

只是为了增强程序的可读性,建议:

● 控制器类上使用:Controller

● service类上使用:Service

● dao类上使用:Repository

他们都是只有一个value属性。value属性用来指定bean的id,也就是bean的名字。

Spring loC注解之声明Bean注解_@Service

2. Spring注解的使用  73

如何使用以上的注解呢?

● 第一步:加入aop的依赖

● 第二步:在配置文件中添加context命名空间

● 第三步:在配置文件中指定扫描的包

● 第四步:在Bean类上使用注解

第一步:加入aop的依赖

我们可以看到当加入spring-context依赖之后,会关联加入aop的依赖。所以这一步不用做。

Spring loC注解之声明Bean注解_@Component_02

第二步:在配置文件中添加context命名空间

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

</beans>

第三步:在配置文件中指定要扫描的包

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!--给Spring框架指定要扫描哪些包中的类-->
    <context:component-scan base-package="com.powernode.spring6.bean"/>
</beans>

第四步:在Bean类上使用注解

package com.powernode.spring6.bean;

import org.springframework.stereotype.Component;

//Spring注解的使用  73
@Component("userBean")
public class User {

}
package com.powernode.spring6.bean;

import org.springframework.stereotype.Controller;

/**
 * Spring注解的使用  73
 **/
@Controller("vipBean") // 如果属性名是value的话,这个属性名可以省略。
public class Vip {
}
package com.powernode.spring6.bean;

import org.springframework.stereotype.Service;

/**
 * Spring注解的使用  73
 **/
@Service("orderBean") // 如果你把整个value属性全部省略了,bean有没有默认的名称?有:类名首字母变小写就是bean的名字。
public class Order {
}
package com.powernode.spring6.bean;

import org.springframework.stereotype.Repository;

/**
 * Spring注解的使用  73
 **/
@Repository("studentBean")
public class Student {
}

测试

//Spring注解的使用  73
    @Test
    public void testBeanComponent(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        User userBean = applicationContext.getBean("userBean", User.class);
        System.out.println(userBean);
        Vip vipBean = applicationContext.getBean("vipBean", Vip.class);
        System.out.println(vipBean);

        //Order类和Student类我们不给value值,使用默认的
        // 如果你把整个value属性全部省略了,bean有没有默认的名称?有:类名首字母变小写就是bean的名字。
        //Order orderBean = applicationContext.getBean("orderBean", Order.class);
        Order orderBean = applicationContext.getBean("order", Order.class);
        System.out.println(orderBean);
        //Student studentBean = applicationContext.getBean("studentBean", Student.class);
        Student studentBean = applicationContext.getBean("student", Student.class);
        System.out.println(studentBean);

//        OrderService orderService = applicationContext.getBean("orderService", OrderService.class);
//        System.out.println(orderService);
//
//        OrderDao orderDao = applicationContext.getBean("orderDao", OrderDao.class);
//        System.out.println(orderDao);
    }

Spring loC注解之声明Bean注解_@Repository_03

3. 解决多包扫描问题  74

3.1 如果是多个包怎么办?有两种解决方案: 74

3.1.1 第一种:在配置文件中指定多个包,用逗号隔开。

com.powernode.spring6包下有两个包一个bean一个dao

package com.powernode.spring6.dao;

import org.springframework.stereotype.Component;

/**
 * Spring注解的使用  73
 **/
@Component
public class OrderDao {
}
<!--多个包,使用逗号隔开。-->
    <context:component-scan base-package="com.powernode.spring6.bean,com.powernode.spring6.dao"/>
OrderDao orderDao = applicationContext.getBean("orderDao", OrderDao.class);
        System.out.println(orderDao);

Spring loC注解之声明Bean注解_@Bean_04

3.1.2 第二种:指定多个包的共同父包。 74

com.powernode.spring6包下有两个包一个bean一个dao

package com.powernode.spring6.dao;

import org.springframework.stereotype.Component;

/**
 * Spring注解的使用  73
 **/
@Component
public class OrderDao {
}
<!--多个包,也可以指定这多个包共同的父包,但是这肯定要牺牲一部分效率。-->
    <context:component-scan base-package="com.powernode.spring6"/>

//解决多包问题  74
        OrderDao orderDao = applicationContext.getBean("orderDao", OrderDao.class);
        System.out.println(orderDao);

Spring loC注解之声明Bean注解_@Controller_05

4. 选择性实例化Bean  75

假设在某个包下有很多Bean,有的Bean上标注了Component,有的标注了Controller,有的标注了Service,有的标注了Repository,现在由于某种特殊业务的需要,只允许其中所有的Controller参与Bean管理,其他的都不实例化。这应该怎么办呢?

use-default-filters="true" 表示:使用spring默认的规则,只要有Component、Controller、Service、Repository中的任意一个注解标注,则进行实例化。

use-default-filters="false" 表示:不再spring默认实例化规则,即使有Component、Controller、Service、Repository这些注解标注,也不再实例化。

 表示只有Controller进行实例化。

   <!--
        第一种解决方案:  75
            use-default-filters="false"
            如果这个属性是false,表示com.powernode.spring6.bean2包下所有的带
            有声明Bean的注解全部失效。@Component @Controller @Service @Repository全部失效。
    -->
     <context:component-scan base-package="com.powernode.spring6.bean2" use-default-filters="false">
        <!--只有@Repository @Service 被包含进来,生效。-->
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
    </context:component-scan>

也可以将use-default-filters设置为true(不写就是true),并且采用exclude-filter方式排出哪些注解标注的Bean不参与实例化:

<!--
        第二种解决方案: 75
            use-default-filters="true"
            如果这个属性的值是true,表示com.powernode.spring6.bean2下的所有的带有声明Bean的注解全部生效。

            use-default-filters="true" 默认值就是true,不用写。
    -->
    <context:component-scan base-package="com.powernode.spring6.bean2">
        <!--@Controller注解失效-->
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
package com.powernode.spring6.bean2;

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

/**
 * 选择性实例化Bean  75
 **/
@Component
public class A {
    public A() {
        System.out.println("A的无参数构造方法执行");
    }
}

@Controller
class B {
    public B() {
        System.out.println("B的无参数构造方法执行");
    }
}

@Service
class C {
    public C() {
        System.out.println("C的无参数构造方法执行");
    }
}

@Repository
class D {
    public D() {
        System.out.println("D的无参数构造方法执行");
    }
}

@Controller
class E {
    public E() {
        System.out.println("E的无参数构造方法执行");
    }
}
//选择性实例化Bean  75
    @Test
    public void testChoose(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-choose.xml");
    }

Spring loC注解之声明Bean注解_@Service_06