注解本身没有功能的,就和 xml 一样。注解和 xml 都是一种元数据,元数据即解释数据的数据,这就是所谓配置。
spring中包含的注解
1.生命Bean注解
@Controller:控制器层【controller】,一般都在控制层使用
@Service:业务逻辑层【service】,一般都在业务逻辑层使用
@Repository:数据访问层【dao】,一般都在数据访问层使用
@component:给不属于以上基层组件的加此注解,偷懒的话可以在所有层使此注解。
注意:虽然我们把注解分成给不同层次加,但是在spring看来注解可以在任意层使用,spring底层不会给具体的层次验证注解,这么写的目的只是为了提高可读性,最偷懒的就是给spring容器中的Bean对象直接添加@component注解。
代码:
<properties>
<lombok.version>1.18.10</lombok.version>
<spring.version>5.2.3.RELEASE</spring.version>
<logging.version>1.2</logging.version>
<alibaba.version>1.1.8</alibaba.version>
<mysql.version>8.0.17</mysql.version>
<junit.version>4.12</junit.version>
</properties>
<dependencies>
<!--引入common-logging-->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>${logging.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${alibaba.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
使用注解的时候需要告诉包,在那个包下面去扫描,一般定义的时候写上相同包的路径,context:component-scan 需要导入命名空间 没有配置指定的扫描包路径,会报异常找不到想要的Bean对象:org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'personController' available
配置扫描包需要先导入命名空间,一般都是自动导入,没办法自动导入就得自己手写
xmlns:context="http://www.springframework.org/schema/context" http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
applicationContext.xml 扫包配置
<context:component-scan base-package="com.zcm.spring01"></context:component-scan>
测试代码
package com.zcm.test;
import com.zcm.spring01.controller.*;
import org.junit.*;
import org.springframework.context.support.*;
/**
* @program: demo
* @ClassName:Test01
* @Description:
* @Author:zcm
* @Date:2021/2/25 15:05
*/
public class Test01 {
@Test
public void test() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
PersonController controller = context.getBean("applicationContext.xml", PersonController.class);
controller.getPerson();
}
}
使用注解的时候没有XML中的id和class一样来识别,如何来识别Bean对象的呢?默认是当前的类对象的首字母小写后作为id来识别的,如果需要改变名称在此注解上面加value的参数值即可。
@Controller("personController")
public class PersonController {}
@Service("personService")
public class PersonServiceImpl implements PersonService {}
@Repository("personDao")
public class PersonDao {}
@Component("config")
public class Config {
public void get() {
System.out.println("这个是配置文件~~~");
}
}
2.自动注入的注解
@Autowired:spring提供的
@Resource:JDK提供的
@Autowired
private PersonService personService2;
@Resource
private PersonService personService2;
注意
@Autowired注解,默认情况下按照ByType来进行装配的,如果找不到就报错,找到直接赋值,需要注意的是,如果有多个类型一样的Bean对象,此时会直接按照id查找,默认的id是类名首字母小写【驼峰的命名格式】,找到了直接注入,不然就报错,如果想要自己规定命名可以通过注解@Qualifier,当@Autowired添加在方法上的时候,此方法在创建对象的时候回默认调用,同时方法中的参数会自动装配。
@Qualifier:注解也可以定义在方法参数列表中,可以指定当前属性的id的属性。将名字指定成personService之后,personService2就会被覆盖了。
@Autowired
@Qualifier("personService")
private PersonService personService2;
@Resource和@Autowired都可以主动注入,但是他们之间还是有区别的?
@Resource可以在其他的框架中使用,@Autowired支持的比较单一,@Resource是按照名称进行装配的,如果名字找不到,那么就使用类型装配 而@Autowired是按照类型进行装配,如果类型找不到会使用使用名字进行查找装配,若果找到两个相同类型的Bean,又根据名字找不到,这时候运行就会包异常:
dependencies failed; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.zcm.spring01.service.PersonService' available: expected single matching bean but found 2: personService,personServiceImpl2
3.注解的Bean作用域
在XML文件中可以配置Bean对象作用域,在注解中也有可以使用@Scope(value = "prototype")【多例】或者@Scope(value = "Singleton")【单例】
@Scope(value = "prototype")
@Controller("personController")
public class PersonController {}
4.扫描包范围
在xml配置了这个标签后,spring可以自动去扫描base-pack下面或者子包下面的java文件,如果扫描到有@Component @Controller@Service等这些注解的类,则把这些类注册为bean
注意:如果配置了<context:component-scan>那么<context:annotation-config/>标签就可以不用再xml中配置了,因为前者包含了后者。另外<context:annotation-config/>还提供了两个子标签
1. <context:include-filter>
2. <context:exclude-filter>
include-filter:表示要包含扫描的注解,一般不会定义此规则,但是如果引入的第三方包中包含注解,此时就需要使用此标签来进行标识。
exclude-filter:表示要排除扫描的注解,使用较多 。
type:规则的类型
expression:表达式
assignable:可以指定对应的类的名称。但是表达式必须是完全限定名
annotation:按照注解来进行排序,但是表达式中必须是注解的完全限定名
regex:使用正则表达式的方式,一般不用
aspectj:使用切面的方式,一般不用
custom:使用自定义的方式,可以自己定义自己的筛选规则,一般不用
问题:如果现在要求只扫描controller包下的类,不扫描配置包中的Config类。
<context:component-scan base-package="com.zcm.spring01">
<!-- 只扫描-->
<context:include-filter expression="com.zcm.spring01.controller.PersonController" type="assignable"/>
<!-- 不扫描-->
<context:exclude-filter type="assignable" expression="com.zcm.spring01.config.Config"/>
</context:component-scan>
注意:加上这个配置之后,这时候获取config,Controller类及它的子包service下注解@Service,@Resorce之外的类就会报异常: