Spring注解开发IOC

一.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符合规则注入成功

猜你喜欢

转载自blog.csdn.net/u014203449/article/details/86559350