环境搭建
4.0.0
com.spring.test
spring-annotation
1.0-SNAPSHOT
org.springframework
spring-context
4.3.12.RELEASE
org.springframework
spring-aspects
4.3.12.RELEASE
org.springframework
spring-jdbc
4.3.12.RELEASE
junit
junit
4.12
test
javax.inject
javax.inject
1
c3p0
c3p0
0.9.1.2
mysql
mysql-connector-java
5.1.44
bean
package com.ming.beans;
public class Person {
private String name;
private int age;
public Person() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
编写配置类
给容器中注册了一个bean,类型为返回值类型,id 默认使用方法名为id
@Configuration
public class MainConfig {
/**
* 给容器中注册了一个bean,类型为返回值类型,id 默认使用方法名为id
* @return
*
* 修改bean的名字
* 1.修改方法名
* 2.在@Bean 注解中指定名字 @Bean("person02")
*/
@Bean("person02")
public Person person(){
return new Person("10", 20);
}
}
Spring 使用xml 注入bean
测试代码
public class MainTest {
public static void main(String[] args){
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
Person bean = applicationContext.getBean(Person.class);
System.out.println(bean);
/**
* 按照类型获取bean的名字(默认注入bean的方法名字)
*/
String[] beanNamesForType = applicationContext.getBeanNamesForType(Person.class);
for (String s : beanNamesForType) {
System.out.println(s);
}
}
}
运行结果
Person [name=10, age=20, nickName=null]
person02
Process finished with exit code 0
而在实际开发中会经常使用包扫描,只要标注了@Controller、@Service、@Repository,@Component 注解的类会自动加入到容器中
Spring xml 包扫描
Spring使用注解 包扫描 @ComponentScan
@ComponentScan("com.spring.annotation")
@Configuration
public class MainConfig {
/**
* 给容器中注册了一个bean,类型为返回值类型,id 默认使用方法名为id
* @return
*
* 修改bean的名字
* 1.修改方法名
* 2.在@Bean 注解中指定名字 @Bean("person02")
*/
@Bean("person02")
public Person person(){
return new Person("10", 20);
}
}
1.添加bean
@Controller
public class BookController {
}
@Repository
public class BookDao {
}
@Service
public class BookService {
}
2.测试
@Test
public void test(){
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
/**
* 获取容器中所有bean定义的名字
*/
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}
3.测试结果
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
bookController
bookDao
bookService
person02
Process finished with exit code 0
注意:mainConfig 配置类也是一个组件 因为@Configuration 注解中标有@Component
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
String value() default "";
}
@ComponentScan 包含过滤和排除过滤
ComponentScan.Filter[] includeFilters() default {}; 按照某些规则排除组件
ComponentScan.Filter[] excludeFilters() default {}; 指定扫描的时候只需要包含哪些组件
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
@AliasFor("basePackages")
String[] value() default {};
@AliasFor("value")
String[] basePackages() default {};
Class>[] basePackageClasses() default {};
Class extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
Class extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;
ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;
String resourcePattern() default "**/*.class";
/**/
boolean useDefaultFilters() default true;
ComponentScan.Filter[] includeFilters() default {};
ComponentScan.Filter[] excludeFilters() default {};
boolean lazyInit() default false;
@Retention(RetentionPolicy.RUNTIME)
@Target({})
public @interface Filter {
FilterType type() default FilterType.ANNOTATION;
@AliasFor("classes")
Class>[] value() default {};
@AliasFor("value")
Class>[] classes() default {};
String[] pattern() default {};
}
}
FilterType 指定不同的包含/排除 规则
package org.springframework.context.annotation;
public enum FilterType {
ANNOTATION,
ASSIGNABLE_TYPE,
ASPECTJ,
REGEX,
CUSTOM;
private FilterType() {
}
}
例如:我们按照注解类型排除 Controller.class, Service.class, Repository.class
@ComponentScan(value = "com.spring.annotation", excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Service.class, Repository.class})
})
@Configuration
public class MainConfig {
/**
* 给容器中注册了一个bean,类型为返回值类型,id 默认使用方法名为id
* @return
*
* 修改bean的名字
* 1.修改方法名
* 2.在@Bean 注解中指定名字 @Bean("person02")
*/
@Bean("person02")
public Person person(){
return new Person("10", 20);
}
}
测试结果(容器中已经没有 BookController BookService BookServie这三个bean)
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
person02
Process finished with exit code 0
包含过滤 includeFilters 如果想要只包含 Controller 注解的bean,如下配置
注意:需要添加 useDefaultFilters = false
@ComponentScan(value = "com.spring.annotation", includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,
classes = {Controller.class})},useDefaultFilters = false)
@Configuration
public class MainConfig {
/**
* 给容器中注册了一个bean,类型为返回值类型,id 默认使用方法名为id
* @return
*
* 修改bean的名字
* 1.修改方法名
* 2.在@Bean 注解中指定名字 @Bean("person02")
*/
@Bean("person02")
public Person person(){
return new Person("10", 20);
}
}
对比Spring xml 配置
单元测试
@Test
public void test(){
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
/**
* 获取容器中所有bean定义的名字
*/
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}
结果如下(可以看到只有Controller注解的bean在容器中)
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
bookController
person02
Process finished with exit code 0
我们还可以使用@ComponentScans 来指定 扫描策略
ComponentScans 注解结构 如下
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
public @interface ComponentScans {
ComponentScan[] value();
}
可以看到其内部是一个ComponentScan[] 数组,所以我们可以在其中指定多个ComponentScan
@ComponentScans(value = {
@ComponentScan(value = "com.spring.annotation", includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,
classes = {Controller.class})},useDefaultFilters = false)
})
@Configuration
public class MainConfig {
/**
* 给容器中注册了一个bean,类型为返回值类型,id 默认使用方法名为id
* @return
*
* 修改bean的名字
* 1.修改方法名
* 2.在@Bean 注解中指定名字 @Bean("person02")
*/
@Bean("person02")
public Person person(){
return new Person("10", 20);
}
}
FilterType.ASSIGNABLE_TYPE 指定不同的类型
例如,包含Controller 注解的bean 和 BookService类型的bean
@ComponentScans(value = {
@ComponentScan(value = "com.spring.annotation", includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class}),
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {BookService.class})
},useDefaultFilters = false)
})
@Configuration
public class MainConfig {
/**
* 给容器中注册了一个bean,类型为返回值类型,id 默认使用方法名为id
* @return
*
* 修改bean的名字
* 1.修改方法名
* 2.在@Bean 注解中指定名字 @Bean("person02")
*/
@Bean("person02")
public Person person(){
return new Person("10", 20);
}
}
FilterType.CUSTOM:使用自定义规则
1.编写MyTypeFilter 并实现 TypeFilter 接口
2.match方法中 实现自定义规则
/**
* 自定义过滤规则
*/
public class MyTypeFilter implements TypeFilter {
/**
*
* @param metadataReader
* @param metadataReaderFactory
* @return
* @throws IOException
* metadataReader:读取到的当前正在扫描的类的信息
* metadataReaderFactory:可以获取到其他任何类信息的
*
*
*/
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
// TODO Auto-generated method stub
//获取当前类注解的信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
//获取当前正在扫描的类的类信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
//获取当前类资源(类的路径)
Resource resource = metadataReader.getResource();
String className = classMetadata.getClassName();
System.out.println("--->"+className);
if(className.contains("er")){
return true;
}
return false;
}
}
3.使用实例(当前扫描到的类,类名中包含er,就会注入到容器中)
@ComponentScans(value = {
@ComponentScan(value = "com.spring.annotation", includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class}),
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {BookService.class}),
@ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class})
},useDefaultFilters = false)
})
@Configuration
public class MainConfig {
/**
* 给容器中注册了一个bean,类型为返回值类型,id 默认使用方法名为id
* @return
*
* 修改bean的名字
* 1.修改方法名
* 2.在@Bean 注解中指定名字 @Bean("person02")
*/
@Bean("person02")
public Person person(){
return new Person("10", 20);
}
}
小总结:
@ComponentScan value:指定要扫描的包
excludeFilters = Filter[] :指定扫描的时候按照什么规则排除那些组件
includeFilters = Filter[] :指定扫描的时候只需要包含哪些组件
FilterType.ANNOTATION:按照注解
FilterType.ASSIGNABLE_TYPE:按照给定的类型;
FilterType.ASPECTJ:使用ASPECTJ表达式
FilterType.REGEX:使用正则指定
FilterType.CUSTOM:使用自定义规则