一、@Controller,@Service,@Repository,@Component注解
创建一个新的工程spring-bean-anno,并导入依赖
<properties> <spring-version>5.3.13</spring-version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring-version}</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.16</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.14</version> </dependency> </dependencies> 复制代码
新建四个包controller,service,dao,entity,分别增加四个类UserController,UserService,UserDao,User
public class UserController { } 复制代码
public class UserService { } 复制代码
public class UserDao { } 复制代码
public class User { private String username; private String password; private String email; private String signature; // 此处省略getter/setter/toString方法 } 复制代码
在前三个类上加上注解@Controller,@Service,@Repository
- @Controller:给controller包中的xxxController加上这个注解
- @Service:给service包中的XxxService实现类添加这个注解
- @Repository:给持久层增加这个注解
- @Component:给任何注册到Spring容器中的组件或类添加这个注解
具体操作为:先在类上加相应注解,再增加xml配置自动扫描范围
resources目录下新建一个annotation.xml配置文件配置扫描范围
<?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:util="http://www.springframework.org/schema/util" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="com.citi"> </context:component-scan> </beans> 复制代码
增加测试类
public class AnnotationTest { @Test public void testGetBeanByAnnotation(){ ApplicationContext context = new ClassPathXmlApplicationContext("classpath:annotation.xml"); String[] beanDefinitionNames = context.getBeanDefinitionNames(); for (String beanDefinitionName : beanDefinitionNames) { System.out.println(beanDefinitionName); } } } 复制代码
执行测试方法,默认Bean的ID为类名首字母小写
自定义bean的id只需要在注解后添加bean的id即可,如@Controller("controller"),再次执行测试
使用注解和xml配置默认都是单例模式,注解模式使用多例需要在类上添加@Scope注解,在UserController类上增加@Scope(value = "prototype"),增加测试方法
@Test public void testGetBeanByAnnotationWithPrototype(){ ApplicationContext context = new ClassPathXmlApplicationContext("classpath:annotation.xml"); UserController userController = context.getBean(UserController.class); UserController userController1 = context.getBean(UserController.class); System.out.println(userController == userController1); } 复制代码
执行测试,控制台打印出false
对于自定义的类要加入到容器中可以使用注解的方式,而对于一些工具类源码如数据库连接池就没有办法加注解,只能通过bean xml配置的方式注册到容器中去,通过注解+xml配置结合可以将任意组件加入到容器中去
二、component-scan,exclude-filter,include-filter标签
<context:component-scan> 标签默认全部配置的包中的全部加了注解的组件,如果想要排除某些组件需要在标签内使用exclude-filter标签,exclude-filter有type和expression两个属性
- type=“annotation”:指定按照注解进行排除,expression则为注解的全类名
- type=“assignable":指定排除具体的类,expression则为具体类的全类名
- type="aspectj":aspectj表达式,expression则为具体表达式内容
- type="customer":自定义实现TypeFilter接口
- type="regex":正则表达式排除
annotation方式排除
xml中component-scan标签下增加配置,排除@Controller注解标注的Bean
<context:component-scan base-package="com.citi"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> 复制代码
执行testGetBeanByAnnotation测试方法,控制台输出不包含userController
assignable方式排除
注销原来的配置,增加xml配置,排出userService
<context:component-scan base-package="com.citi"> <context:exclude-filter type="assignable" expression="com.citi.service.UserService"/> </context:component-scan> 复制代码
同样执行testGetBeanByAnnotation测试方法,控制台输出不包含userService
指定只扫描哪些可以使用include-filter标签,位置同样放在component-scan标签内,属性及Value都与exclude-filter一致,使用include-filter首先要禁用默认全部扫描
注销xml中原来的配置,新增只扫描UserService组件的配置
<context:component-scan base-package="com.citi" use-default-filters="false"> <context:include-filter type="assignable" expression="com.citi.service.UserService"/> </context:component-scan> 复制代码
执行testGetBeanByAnnotation测试方法,控制台输出只包含userService
三、依赖注入@Autowire注解
在UserDao中增加方法
public void insert(User user){ System.out.println(this.getClass().getName() + "的insert方法被调用"); } 复制代码
@Autowire是按照类型注入,如果找不到会报错,如果找到多个相同类型的Bean会怎么样?存在多个同类型的Bean按照属性名为id继续装配 新增一个UserDaoExt类,继承UserDao,并加入容器中
@Repository public class UserDaoExt extends UserDao { @Override public void insert(User user) { System.out.println(this.getClass().getName() + "的insert方法被调用"); super.insert(user); } } 复制代码
新增测试类
public class AutowireAnnotationTest { @Test public void testGetBeanByAnnotation(){ ApplicationContext context = new ClassPathXmlApplicationContext("classpath:annotation.xml"); UserService userService = context.getBean("userService", UserService.class); userService.save(new User()); String[] beanDefinitionNames = context.getBeanDefinitionNames(); for (String beanDefinitionName : beanDefinitionNames) { System.out.println(beanDefinitionName); } } } 复制代码
userService调用的是userDao的insert方法,说明是按照属性名来装配的
将UserService中属性名改为useDaoExt,再次执行测试,输出UserDaoExt的insert方法被调用,可以说明当存在多个相同类型的Bean时,@Autowire注解会根据属性名作为Bean的ID进行自动装配
@Qualifier()指定装配的Bean的ID
UserService中属性增加@Qualifier()注解
@Service public class UserService { @Qualifier("userDao") @Autowired private UserDao userDaoExt; public void save(User user){ System.out.println(this.getClass().getName() + "的save方法被调用"); userDaoExt.insert(user); } } 复制代码
再次执行测试,@Qualifier注解指定的userDao被调用