2021/10/30 西安 spring【2】注解的标记和扫描,自动装配

注解标记和扫描

1、注解的标记

若IOC容器所扫描的类型被指定的注解所标识,此时该类型就会被作为bean交给IOC容器管理。

注解就是一个标记,本身没有功能,注解是通过反射来解析

被指定的注解:在spring中标识组件的注解有4个:

@Component:将类标识为普通组件
@Controller:将类标识为控制层组件
@Service:将类标识为业务层组件
@Repository:将类标识为持久层组件

以上四个注解,功能没有任何区别,作用都是将注解标记的类标识为IOC容器的bean。但是对于程序员来说,可以通过不同的注解标识不同的组件

注解标记:注意不能给SecretBookService接口加注解,要给它的实现类加注解才对(不是说不可以给接口加注解,是可以给接口加注解的)

@Controller
public class SecretBookController {
    SecretBookService secretBookService;
    public void showSecretBook(){
        secretBookService.showSecretBook();
    }
}

@Service
public class SecretBookServiceImpl implements SecretBookService {
    @Override
    public void showSecretBook() {
        System.out.println("恭喜宿主绑定成功");
    }
}

2、默认id

通过 注解+扫描 所配置的组件,在IOC容器中有默认的id,即 类名所对应的小驼峰
若要自定义bean的id,可以使用标识组件的四个注解的value属性设置自定义的bean的id 


3、注解的扫描

在applicationContext.xml中,加入扫描注解的标签<component-scan>

<?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 https://www.springframework.org/schema/context/spring-context.xsd">

<!--  扫描组件-最基本的扫描方式-->
    <context:component-scan base-package="com.atguigu.spring" >
    </context:component-scan>

</beans>

测试代码:

ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
SecretBookController secretBookController = ac.getBean(SecretBookController.class);
SecretBookServiceImpl secretBookServiceImpl = ac.getBean(SecretBookServiceImpl.class);
System.out.println(secretBookController);
System.out.println(secretBookServiceImpl);

测试结果:说明SecretBookController,SecretBookServiceImpl确确实实被IOC容器所管理了


4、扫描排除

context:exclude-filter:排除对组件的扫描,即不扫描某些类型

type:设置排除和包含的方式,type="annotation|assignable"

annotation:表示通过注解的类型进行排除和包含
assignable:表示通过类的类型进行排除和包含

type=“annotation”右键复制注解的全类名

annotation:表示通过注解的类型进行排除和包含

    <context:component-scan base-package="com.atguigu.spring">
<!--        根据注解排除-->
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

type=“assignable”右键复制类的全类名

assignable:表示通过类的类型进行排除和包含

    <context:component-scan base-package="com.atguigu.spring">
<!--  根据类的类型排除-->
      <context:exclude-filter type="assignable"
                                expression="com.atguigu.spring.controller.SecretBookController"/>
    </context:component-scan>

5、扫描包含

context:include-filter:包含对组件的扫描,即只扫描某些类型

    <context:component-scan base-package="com.atguigu.spring" use-default-filters="false">
<!--  只扫描通过context:include-filter所设置的组件-->
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

use-defaultfilters="false" 表示不使用组件扫描的默认规则(即不扫描指定包下的类型)只扫描通过context:include-filter所设置的组件

默认规则:将指定包下所有的类型全部扫描

但是,要是只想扫描Controller包下的组件,下面这种方式他不香吗

<context:component-scan base-package="com.atguigu.spring.controller" >
</context:component-scan>

自动装配

1、自动装配(XML方式)

自动装配:装配就是注入,自动为类类型(接口、抽象类也行)的属性赋值。自动装配指ref的属性

根据指定的策略,把IOC某一个类型匹配的bean赋值给 “自动装配的bean的ref属性”。

通过autowire设置自动装配的策略

autowire="default|no|byType|byName"
default|no:效果一致,表示不装配

<bean id="heroController" 
class="com.atguigu.spring.controller.HeroController" 
autowire="byType"></bean>

byType:根据自动装配的属性的类型自动装配,根据类型去匹配某个兼容类型的bean,有且只能有一个类型匹配的bean

若一个都没有,则没有任何一个bean能够为当前属性自动赋值,则当前属性为默认值
若有多个bean能够为当前属性赋值,会抛出异常NoUniqueBeanDefinitionException

byName:将自动装配的属性的属性名作为bean的id在IOC容器中匹配相对应的bean进行赋值

要保证类型匹配的情况下,根据byName匹配某个bean为属性赋值
若没有任何一个bean的id和属性名一致,则不装配,即当前属性为默认值

在 applicationContext.xml中,只写了如下。注意我并没有使用<property>。

<bean id="heroController" class="com.atguigu.spring.controller.HeroController" autowire="byType"></bean>
<bean id="heroService" class="com.atguigu.spring.service.impl.HeroServiceImpl" autowire="byType"></bean>
<bean id="heroDao" class="com.atguigu.spring.dao.impl.HeroDaoImpl" autowire="byType"></bean>

测试代码如下:

ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
HeroController heroController = ac.getBean(HeroController.class);
heroController.saveHero();

HeroController中,一定要加set方法。

public class HeroController {
    HeroService heroService;

    public void setHeroService(HeroService heroService) {
        this.heroService = heroService;
    }

    public void saveHero(){
        heroService.saveHero();
    }
}

HeroService heroService; 并没有给赋初值,但是结果也没有报空指针异常,反而调到了底层dao里的方法!原因便是自动装配了,

从 applicationContext.xml中可知,HeroController开启了自动装配。则会自动为类类型的属性赋值,即自动为heroService赋值。赋值的策略是byType,即在IOC容器中根据自动装配的属性的类型匹配某个bean为当前属性自动赋值


2、@Autowired使用演示

自动装配 @Autowired加到成员变量上,不再需要set方法。

当然,@Autowired注解也可以标记在构造器和set方法上吗,但是没必要,花里胡哨的

@Controller
public class SecretBookController {
    @Autowired
    SecretBookService secretBookService;

    public void showSecretBook(){
        secretBookService.showSecretBook();
    }
}

此时applicationContext.xml中,真的是孤苦伶仃。只配置了包扫描 

测试代码:

ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
SecretBookController secretBookController = ac.getBean(SecretBookController.class);
secretBookController.showSecretBook();

测试结果:成功调到了SecretBookServiceImpl的方法


3、@Autowired原理

通过@Autowired实现自动装配的功能

@Autowired:先根据byType方式,若通过类型匹配到了多个bean,会转为byName的方式匹配bean,为属性赋值。

a>先通过byType的方式,根据自动装配的属性的类型,匹配“IOC容器中的bean”为属性赋值
①在IOC容器中没有任何一个类型匹配的bean,此时抛出异NoSuchBeanDefinitionException

测试:删除@Service注解,再跑上面程序。

②可以在@Autowired注解中设置属性required=false,该属性默认值为true,为true表示当前属性必须能够自动装配,否则直接抛出异常NoSuchBeanDefinitionException,若设置为false,则表示能装配则装配,若没有匹配的bean,则使用默认值


b>若通过类型匹配到了多个bean,此时转换为byName的方式匹配bean,为属性赋值
①若将要自动装配的属性的属性名作为bean的id匹配,没有匹配成功,此时抛出异常NoUniqueBeanDefinitionException

测试:


    @Autowired
    SecretBookService secretBookService;

此时IOC容器中有俩个SecretBookServiceImpl类型的bean,beanid分别是xml方式配置的service和默认的secretBookServiceImpl

②解决多个bean的id和要自动装配的属性的属性名都不匹配(就是我们上面那种情况),有两种解决方案:

方式一:

通过标识组件的注解的value属性设置bean的自定义的id,和要自动装配的属性的属性名一致

方式二:

通过@Qualifier注解的value属性设置要为属性自动装配的bean的id

或者


4、@Resource

@Resource 和@Autowired都是用来自动装配,放在属性字段上。@Autowired用的更多。

1、@Resource是JDK原生的注解,@Autowired是Spring2.5 引入的注解

2、@Resource默认byname实现,找不到名字,再通过bytype实现。@Autowired是通过bytype自动装配的


摆脱XML配置?

@Value

那属性的注入呢?比如说name的注入,用@Value等价于xml里的:

<property name="name" value="kuangshen">  


@Scope

 当然作用域也是可以用注解@Scope指定的,如下把User类设置为原型模式

@Component
@Scope("prototype")
public class User{

}

@Configuration和@Bean

代表这是一个配置类(会在之后springboot中详解)

  1.  @Configuation等价于<beans></beans>
  2.  @Bean等价于<bean></bean>
  3.  @ComponentScan等价于<context:component-scan base-package=”com.dxz.demo”/>
@Configuration  //配置类,本身也是@Component
@ComponentScan("com.cn.spring")
public class LongConfig {
    @Bean //相当于xml配置中的<bean/>
    public UserDao getUser(){   //getUser方法名,就相当于bean标签的id属性
        return new UserDao(); //返回注入的bean的对象
    }
}

 那这种纯Java的配置方式,怎么取到容器里注册的bean呢

@Configuration  //配置类,本身也是@Component
@ComponentScan("com.cn.spring")
public class LongConfig {
    @Bean //相当于xml配置中的<bean/>
    public UserDao getUser(){   //getUser方法名,就相当于bean标签的id属性
        return new UserDao(); //返回注入的bean的对象
    }

    public static void main(String[] args) {
        //通过AnnotationConfig上下文来获取容器,通过LongConfig.class(配置类)加载
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(LongConfig.class);
        UserDao dao = (UserDao)context.getBean("getUser");
        dao.add();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值