Spring5-IOC容器-基于注解进行Bean管理

一、Bean管理包括两个操作:
1、Spring创建对象
2、Spring注入属性
二、什么是注解?
1、注解是代码中的特殊标记,格式为:@注解名称(属性名称 = 属性值, 属性名称 = 属性值…)
2、注解可以使用在类、属性、方法
3、使用注解的目的:简化XML配置文件的使用
4、Spring针对Bean管理中对象创建提供的注解有:
(1)@Component
用来标注一个类为Spring容器的Bean。
(2)@Service
一般使用在业务逻辑层、service层。
(3)@Controller
一般使用在web层。
(4)@Repository
一般使用在持久层、Dao层。
*上面四个注解都可以用来创建bean实例
三、实现
操作步骤:
1、引入依赖
除了Spring最基本的依赖以外,还需要aop的依赖在这里插入图片描述
全部的依赖如下:
在这里插入图片描述

2、开启组件扫描
所谓组件扫描就是告诉Spring我们需要在哪些类上面添加注解
3、实现
项目结构:
在这里插入图片描述
UserService类:

package com.java.spring5.Service;

import org.springframework.stereotype.Component;

// 在注解里面的value属性值可以省略不写,如果不写的话会默认值为类的名称。首字母小写,如UserService -> userService
@Component(value = "userService") //等价于<bean id="userService" class="com.java.spring5.Service.UserService" ></bean>
public class UserService {
    String name;

    public void add () {
        System.out.print("userService add...");
    }
}

其实在这里也可以使用@Controller、@Service、@Repository做到一样的效果。
配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       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" >

     <!--开启组件扫描
     第一步:引入context名称空间,如上
     第二步:开启组件扫面,使用context:component-scan标签的base-package属性进行指定我们需要扫描的类的路径
            如果需要扫描多个包,使用,隔开,或者扫描多个包的上层目录-->
    <context:component-scan base-package="com.java.spring5"></context:component-scan>
</beans>

测试方法:

@Test
    public void test1() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean1.xml");
        UserService userService = applicationContext.getBean("userService", UserService.class);
        userService.add();
    }

分析:首先加载配置文件,按照配置文件中的配置区扫描com.java.spring5包,扫描到一个加上注解的UserService类,然后进行创建实例
四、扫描filter配置
如上所示的我们会去扫描com.java.spring5下的所有的类,其实我们是可以单独配置可以扫描哪些,哪些又不可以扫描的。主要是使用context:include-filter、context:exclude-filter两个标签来进行控制,入邪配置文件所述。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       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" >

     <!--开启组件扫描
     第一步:引入context名称空间,如上
     第二步:开启组件扫面,使用context:component-scan标签的base-package属性进行指定我们需要扫描的类的路径
            如果需要扫描多个包,使用,隔开,或者扫描多个包的上层目录-->
    <context:component-scan base-package="com.java.spring5"></context:component-scan>

    <!--实例一:
    use-default-filters="false" 表示现在不使用默认的filter,而是使用自己配置的filter
    context:include-filter 既是配置我们扫描哪些内容。
            type="annotation"则是配置我们扫描注解,
            expression="org.springframework.stereotype.Service"则是扫描配置了注解@service的类-->
    <context:component-scan base-package="com.java.spring5" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
    </context:component-scan>

    <!--实例二:
    与实例一不同,在这里我们扫描com.java.spring5包下的所有类,而使用context:exclude-filter配置不扫描哪些内容的,相同的
            type="annotation"则是配置我们扫描注解,
            expression="org.springframework.stereotype.Controller"则是不扫描配置了注解@Controller的类-->
    <context:component-scan base-package="com.java.spring5">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
</beans>

五、基于注解方式实现属性注入
在这里会涉及到几个注解:
@Autowired:根据属性类型进行自动注入
@Qualifier:根据属性名称进行注入
@Resource :可以根据属性类型、也可以根据属性的名称进行注入
@Value:注入普通类型属性
1、@Autowired注解
第一步:在service和dao中创建出相对应的类,并给类加上创建对象的注解。第二步:在service中注入dao对象,在service类中添加dao类型属性,在属性上面添加注入注解
Dao层的接口以及实现类如下:

package com.java.spring5.Dao;

public interface UserDao {
    void add();
}

package com.java.spring5.Dao;

import org.springframework.stereotype.Repository;

@Repository
public class UserDaoIpml implements  UserDao{
    public void add() {
        System.out.print("userDao add...");
    }
}

Service层

package com.java.spring5.Service;

import com.java.spring5.Dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService2 {
    @Autowired
    UserDao userDao;
    //在这里使用@Autowired注入,是不需要添加set方法,因为Autowired注解使用的时候就已经帮我们封装好了

    public void userServiceAdd() {
        userDao.add();
    }

}

测试类:

@Test
    public  void autoWiredTest() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean1.xml");
        UserService2 userService2 = applicationContext.getBean("userService2", UserService2.class);
        userService2.userServiceAdd();
    }

运行结果:
在这里插入图片描述
注:我们使用注解方法去注入属性的时候,不需要要求注入属性所在的类有set方法,因为已经封装好了。
2、@Qualifier
情景:
如上Dao层中的UserDao接口有一个实现类的话我们可以使用@Autowired按照类型进行注入,但是如果UserDao有多个实现类,如下所示:
在这里插入图片描述
那么运行刚刚的测试方法会抛出异常:

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.java.spring5.Dao.UserDao' available: expected single matching bean but found 2: userDaoIpml,userDaoIpml2
	at org.springframework.beans.factory.config.DependencyDescriptor.resolveNotUnique(DependencyDescriptor.java:220)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1285)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1227)
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:657)
	

揪出其中重要的部分:

No qualifying bean of type 'com.java.spring5.Dao.UserDao' available: expected single matching bean but found 2: userDaoIpml,userDaoIpml2

也就是说有两个实现类,我不知道该选择哪一个进行注入。为了解决这一问题,我们就可使用@Qualifier注解进行注入属性,根据属性名称进行注入。如下:
第一步:给第二个实现类的代码如下:

package com.java.spring5.Dao;

import org.springframework.stereotype.Component;

// 不指定value则默认使用首字母小写的类名作为value
@Component
public class UserDaoIpml2 implements UserDao  {
    @Override
    public void add() {
        System.out.print("UserDaoIpml2 add.....");
    }
}

第二步:给UserDao增加@Qualifier注解

package com.java.spring5.Service;

import com.java.spring5.Dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class UserService2 {
    @Autowired
    @Qualifier(value = "userDaoIpml2")
    UserDao userDao;
    //在这里使用@Autowired注入,UserDao是不需要添加set方法,因为Autowired注解使用的时候就已经帮我们封装好了

    public void userServiceAdd() {
        userDao.add();
    }

}

同样运行上面的测试方法,运行结果:
在这里插入图片描述
可能小伙伴们很疑惑为什么只使用@Qualifier进行注入,我将@Autowired注解去掉,运行会报空指针异常,目前我还不知道为什么。这里可能就需要去读读源码了。
在这里插入图片描述
总结:@Qualifier注解需要和@Autowired注解一起使用,如果单独使用会报空指针异常。
3、@Resource
使用@Resource注入属性与@Autowired注入属性有一个相同的问题:如果一个接口有多个实现类,那如果我们不给@Resource指定实现类的名字也会报异常,异常信息与@Autowired出现异常信息一样。如下是@Resource注解的使用:

package com.java.spring5.Service;

import com.java.spring5.Dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service
public class UserService2 {

//    @Resource
    @Resource(name = "userDaoIpml2")
    UserDao userDao;

    public void userServiceAdd() {
        userDao.add();
    }

}

总结:虽然@Resource注解可以做到根据属性值与属性类型进行注入的功能,但是@Resource不是Spring的,是java的扩展包中,所以Spring并不建议我们使用@Resouce,通常我们使用@Autowired根据属性类型如注入属性。
在这里插入图片描述
4、@value
@Value主要是用来注入String、int等等普通类型的属性
使用如下:

package com.java.spring5.Service;

import com.java.spring5.Dao.UserDao;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service
public class UserService2 {

//    @Resource
    @Resource(name = "userDaoIpml2")
    UserDao userDao;

    @Value(value = "abc")
    String userName;

    public void userServiceAdd() {
        userDao.add();
        System.out.print(this.userName);
    }

}

运行结果:
在这里插入图片描述
六、完全注解
在上面的例子当中,我们虽然比完全使用配置文件时配置文件的类容变少了,但还是会有那么一点繁琐。所谓完全注解,就是在不依赖配置文件去扫描注解。
第一步:创建配置类替换掉xml配置文件
1、使用@Configuration让Spring知道当前类时配置类
2、使用@ComponentScan注解开启扫描注解
basePackages属性:开启扫描包。示例:@ComponentScan(basePackages = {“com.java.spring5”})
相当于我们之前配置文件中的
<context:component-scan base-package=“com.java.spring5”></context:component-scan>
basePackageClasses:开启扫描某个类所在包下的所有注解。

package com.java.spring5.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackages = {"com.java.spring5"})
public class SpringConfig {
}

第二步:对象的创建与属性的注入方式不变,不同的是测试方法,测试方法如下:

@Test
    public void noConfigTest() {
        // 1、加载配置类
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        // 2、得到创建的对象
        UserService2 userService2 = context.getBean("userService2", UserService2.class);
        userService2.userServiceAdd();
    }

运行结果:
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值