環(huán)境搭建
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.spring.test</groupId>
<artifactId>spring-annotation</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.inject/javax.inject -->
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/c3p0/c3p0 -->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.44</version>
</dependency>
</dependencies>
</project>
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
<?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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
<bean id="person" class="com.spring.annotation.bean.Person">
<property name="name" value="zhangsan"></property>
<property name="age" value="20"></property>
</bean>
</beans>
測試代碼
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);
}
}
}
運行結(jié)果
Person [name=10, age=20, nickName=null]
person02
Process finished with exit code 0
而在實際開發(fā)中會經(jīng)常使用包掃描,只要標注了@Controller垂睬、@Service、@Repository抗悍,@Component 注解的類會自動加入到容器中
Spring xml 包掃描
<context:component-scan base-package="com.ming" use-default-filters="false"></context:component-scan>
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.測試結(jié)果
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 {}; 按照某些規(guī)則排除組件
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 指定不同的包含/排除 規(guī)則
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);
}
}
測試結(jié)果(容器中已經(jīng)沒有 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 配置
<context:component-scan base-package="com.test.ming" use-default-filters="false"></context:componentscan>
單元測試
@Test
public void test(){
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
/**
* 獲取容器中所有bean定義的名字
*/
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}
結(jié)果如下(可以看到只有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 注解結(jié)構(gòu) 如下
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
public @interface ComponentScans {
ComponentScan[] value();
}
可以看到其內(nèi)部是一個ComponentScan[] 數(shù)組,所以我們可以在其中指定多個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:使用自定義規(guī)則
1.編寫MyTypeFilter 并實現(xiàn) TypeFilter 接口
2.match方法中 實現(xiàn)自定義規(guī)則
/**
* 自定義過濾規(guī)則
*/
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);
}
}
小總結(jié):
@ComponentScan value:指定要掃描的包
excludeFilters = Filter[] :指定掃描的時候按照什么規(guī)則排除那些組件
includeFilters = Filter[] :指定掃描的時候只需要包含哪些組件
FilterType.ANNOTATION:按照注解
FilterType.ASSIGNABLE_TYPE:按照給定的類型袜蚕;
FilterType.ASPECTJ:使用ASPECTJ表達式
FilterType.REGEX:使用正則指定
FilterType.CUSTOM:使用自定義規(guī)則