一.xml形式组件注册
pom
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.5.RELEASE</version>
</dependency>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="person" class="com.melo.bean.Person">
<property name="name" value="张三"></property>
<property name="age" value="18"></property>
</bean>
</beans>
Person.java
package com.melo.bean;
public class Person {
private String name;
private Integer age;
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Person() {
super();
// TODO Auto-generated constructor stub
}
public Person(String name, Integer age) {
super();
this.name = name;
this.age = age;
}
}
test
@SuppressWarnings("resource")
public static void main(String[] args) {
//ClassPathXmlApplicationContext在类路径下读取xml文件
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
//通过id获取
Person bean = (Person) applicationContext.getBean("person");
//通过class获取
Person bean2 = applicationContext.getBean(Person.class);
System.out.println(bean);
System.out.println(bean2);
}
二.配置类注册@Configuration@Bean
配置类,bean的id默认是方法名,想改名字可以改方法名,或者给@Bean(value="名字")
//配置类=配置文件
@Configuration//告诉spring这是一个配置类
public class MyConfig {
//给容器注册一个bean,类型时返回值的类型,bean的id默认是方法名,想改名字可以改方法名,或者给@Bean(value="名字")
@Bean("person")
public Person p1() {
return new Person("李四", 26);
}
}
test
@SuppressWarnings("resource")
public static void main(String[] args) {
//AnnotationConfigApplicationContext 获取配置类的容器
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
Person bean = (Person) applicationContext.getBean("person");
System.out.println(bean);
//获取此class在容器中的所有bean名字
String[] names = applicationContext.getBeanNamesForType(Person.class);
for(String name:names) {
System.out.println(name);
}
}
三.指定扫描
1
@ComponentScan("com.melo") 扫描指定的包,会扫描@Controller @Service这些注解
//配置类=配置文件
@Configuration//告诉spring这是一个配置类
@ComponentScan("com.melo")
public class MyConfig {
//给容器注册一个bean,类型时返回值的类型,bean的id默认是方法名,想改名字可以改方法名,或者给@Bean(value="名字")
@Bean("person")
public Person p1() {
return new Person("李四", 26);
}
}
@Controller
public class BookController {
}
@Repository
class BookDao {
}
@Service
public class BookService {
}
public class IocTest {
@SuppressWarnings("resource")
@Test
public void test1() {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
//所有定义的bean名字
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for(String name:beanDefinitionNames){
System.out.println(name);
}
}
}
2.过滤扫描
@ComponentScan(value="com.melo",excludeFilters= {})
点击ComponentScan进入
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
//指定只包括哪些
Filter[] includeFilters() default {};
//指定过滤掉哪些
Filter[] excludeFilters() default {};
}
发现可以按数组过滤,Filter数组,Filter也是注解
@Retention(RetentionPolicy.RUNTIME)
@Target({})
@interface Filter {
/**
* The type of filter to use.
* <p>Default is {@link FilterType#ANNOTATION}.
* @see #classes
* @see #pattern
*/
//按那种方式过滤,默认按注解
FilterType type() default FilterType.ANNOTATION;
}
查看枚举FilterType
//按注解排除
ANNOTATION,
//按类
ASSIGNABLE_TYPE,
/**
* Filter candidates matching a given AspectJ type pattern expression.
* @see org.springframework.core.type.filter.AspectJTypeFilter
*/
ASPECTJ,
//正则
REGEX,
//自定义
CUSTOM
}
用注解排除试一下,排除controller 和Repository的注解
//配置类=配置文件
@Configuration//告诉spring这是一个配置类
//@ComponentScan("com.melo")
@ComponentScan(value="com.melo",excludeFilters= {
@Filter(type=FilterType.ANNOTATION,classes= {Controller.class,Repository.class})
})
public class MyConfig {
//给容器注册一个bean,类型时返回值的类型,bean的id默认是方法名,想改名字可以改方法名,或者给@Bean(value="名字")
@Bean("person")
public Person p1() {
return new Person("李四", 26);
}
}
在排除Service时出现了异常,Service is not assignable to interface Annotation还不知道原因
3.只包含扫描
includeFilters
默认规则就是扫描所有,只有禁用原规则,才能有效果,useDefaultFilters=false
//配置类=配置文件
@Configuration//告诉spring这是一个配置类
//@ComponentScan("com.melo")
@ComponentScan(value="com.melo",includeFilters= {
@Filter(type=FilterType.ANNOTATION,classes= {Controller.class,Repository.class})
},useDefaultFilters=false)
public class MyConfig {
//给容器注册一个bean,类型时返回值的类型,bean的id默认是方法名,想改名字可以改方法名,或者给@Bean(value="名字")
@Bean("person")
public Person p1() {
return new Person("李四", 26);
}
}
只有includeFilters指定的注解
4.多个扫描策略
@ComponentScans里面是数组,指定多个ComponentScan
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface ComponentScans {
ComponentScan[] value();
}
//配置类=配置文件
@Configuration//告诉spring这是一个配置类
//@ComponentScan("com.melo")
@ComponentScans({
@ComponentScan(value="com.melo",includeFilters= {
@Filter(type=FilterType.ANNOTATION,classes= {Controller.class,Repository.class})
},useDefaultFilters=false)
})
public class MyConfig {
//给容器注册一个bean,类型时返回值的类型,bean的id默认是方法名,想改名字可以改方法名,或者给@Bean(value="名字")
@Bean("person")
public Person p1() {
return new Person("李四", 26);
}
}
5.其他过滤规则
最常用的是注解和类
FilterType.ASSIGNABLE_TYPE 按照类型过滤
@Configuration//告诉spring这是一个配置类
//@ComponentScan("com.melo")
@ComponentScans({
@ComponentScan(value="com.melo",includeFilters= {
@Filter(type=FilterType.ANNOTATION,classes= {Controller.class,Repository.class}),
@Filter(type=FilterType.ASSIGNABLE_TYPE,classes= {BookService.class})},
useDefaultFilters=false)
})
public class MyConfig {
//给容器注册一个bean,类型时返回值的类型,bean的id默认是方法名,想改名字可以改方法名,或者给@Bean(value="名字")
@Bean("person")
public Person p1() {
return new Person("李四", 26);
}
}
本来BookService在第一个Filter按注解方式没有包含,但在第二个Filter按类的方式包含了
试一下自定义规则,看注释说必须是TypeFilter的实现类
/** Filter candidates using a given custom
* {@link org.springframework.core.type.filter.TypeFilter} implementation.
*/
CUSTOM
metadataReader 获取正在读取类的信息
metadataReaderFactory 一个工厂获取读到的其他类的信息
public interface TypeFilter {
/**
* Determine whether this filter matches for the class described by
* the given metadata.
* @param metadataReader the metadata reader for the target class
* @param metadataReaderFactory a factory for obtaining metadata readers
* for other classes (such as superclasses and interfaces)
* @return whether this filter matches
* @throws IOException in case of I/O failure when reading metadata
*/
boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException;
}
实现一个TypeFilter,输出扫描到的类名
public class MyTypeFilter implements TypeFilter {
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException {
//获取当前类的注解信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
//获取当前了类的类信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
//获取当前资源,类的路径
Resource resource = metadataReader.getResource();
System.out.println(classMetadata.getClassName());
return false;
}
}
只使用自定义的过滤规则
//配置类=配置文件
@Configuration//告诉spring这是一个配置类
//@ComponentScan("com.melo")
@ComponentScans({
@ComponentScan(value="com.melo",includeFilters= {
// @Filter(type=FilterType.ANNOTATION,classes= {Controller.class,Repository.class})
// ,@Filter(type=FilterType.ASSIGNABLE_TYPE,classes= {BookService.class})
@Filter(type=FilterType.CUSTOM,classes= {MyTypeFilter.class})
},
useDefaultFilters=false)
})
public class MyConfig {
//给容器注册一个bean,类型时返回值的类型,bean的id默认是方法名,想改名字可以改方法名,或者给@Bean(value="名字")
@Bean("person")
public Person p1() {
return new Person("李四", 26);
}
}
因为取消了默认扫描策略,所以controllerservice这些都不会注入容器,输出了扫描到的每个类名。又因为自定义扫描规则返回的全是false,所有不会有类被注入容器。myconfig和person是配置类本身的
更改自定义规则,将类名带"er"的返回true注入容器
public class MyTypeFilter implements TypeFilter {
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException {
//获取当前类的注解信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
//获取当前了类的类信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
//获取当前资源,类的路径
Resource resource = metadataReader.getResource();
String className = classMetadata.getClassName();
if(className.contains("er")) {
return true;
}
return false;
}
}
myConfig,person 不是包扫描结果不看。
注意:myTypeFilter虽然没有加注解,但符合我们的规则,并且@ComponentScan(value="com.melo" 扫描的是这个包,所以myTypeFilter也会被扫描到,并且注入
bookController bookService符合规则注入成功