栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring注解驱动开发

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring注解驱动开发

文章目录

1、使用@Configuration和@Bean给容器中注册组件

1.1、xml配置文件方法1.2、注解配置 2、使用@ComponentScan自动扫描组件并指定扫描规则

2.1、xml配置文件方式2.2、注解方式

2.2.1、扫描规则:excludeFilters2.2.2、扫描规则:includeFilters2.2.3、配置多个ComponentScan 3、自定义TypeFilter指定@ComponentScan注解的过滤规则4、使用@Scope注解设置组件的作用域

4.1、单实例和多实例情况下,对象是何时创建的? 5、@Lazy-bean如何实现懒加载?

1、使用@Configuration和@Bean给容器中注册组件

首先创建一个Person类:

public class Person {
    private String name;
    private Integer age;
    
    ......
1.1、xml配置文件方法

创建一个beans.xml,在配置文件中指定标签,其中属性包括id(唯一标识)和class(全类名):


    
    

测试时,使用ClassPathXmlApplicationContext()方法传入xml配置文件的路径来获取一个ApplicationContext对象:

@Test
public void test1(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
    Object person = applicationContext.getBean("person");
    System.out.println(person);
    // Person{name='zhangsan', age=18}
}
1.2、注解配置

创建一个注解类MainConfig,相当于一个配置文件,采用@Configuration注解。

在类中创建一个方法,采用@Bean注解,类型为返回值类型,id默认是用方法名作为id,也可以给@Bean注解传入一个参数,作为id

//配置类==配置文件
@Configuration //告诉spring,这是一个配置类
public class MainConfig {

    //给容器中注册一个Bean;类型为返回值类型,id默认是用方法名作为id
    @Bean("person") //可以传入参数,作为id
    public Person person01(){
        return new Person("lisi", 20);
    }
}

获取Bean时,使用AnnotationConfigApplicationContext()方法传入注解类的class:

@Test
public void test2(){
    ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
    Person person = applicationContext.getBean(Person.class);
    System.out.println(person);
    // Person{name='lisi', age=20}

    String[] beanNamesForType = applicationContext.getBeanNamesForType(Person.class);
    for (String string :
            beanNamesForType) {
        System.out.println(string);
        // person
    }
}

2、使用@ComponentScan自动扫描组件并指定扫描规则

创建BookService、BookController、BookDao类,并分别使用@Service、@Controller、@Repository注解:

@Service
public class BookService {
}
@Controller
public class BookController {
}
@Repository
public class BookDao {
}
2.1、xml配置文件方式

2.2、注解方式

在注解类中添加@ComponentScan注解,并提供value属性的值:

//配置类==配置文件
@Configuration //告诉spring,这是一个配置类
@ComponentScan(value = {"bean", "config", "controller", "dao", "service"})
public class MainConfig {

    //给容器中注册一个Bean;类型为返回值类型,id默认是用方法名作为id
    @Bean("person") //可以传入参数,作为id
    public Person person01(){
        return new Person("lisi", 20);
    }


}

输出一下所有定义的Bean的名字:

@Test
public void test3(){
    ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
    String[] definitionNames = applicationContext.getBeanDefinitionNames();

    for (String name :
            definitionNames) {
        System.out.println(name);
    }
}
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
bookController
bookDao
bookService
person
2.2.1、扫描规则:excludeFilters

看一下@ComponentScan注解的源码:

@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 nameGenerator() default BeanNameGenerator.class;

    Class scopeResolver() default AnnotationScopemetadataResolver.class;

    ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;

    String resourcePattern() default "**
    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();
        System.out.println("--->" + className);

        //如果类名称包含"er"就扫描
        if (className.contains("er")){
            return true;
        }

        return false;
    }
}
//配置类==配置文件
@Configuration //告诉spring,这是一个配置类
@ComponentScan(
               value = {"bean", "config", "controller", "dao", "service"},
               includeFilters = {
                                
                                 @ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class})
               },
               useDefaultFilters = false
               //excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})}
)
//@ComponentScan value:指定要扫描的包
//@ComponentScan excludeFilters = ComponentScan.Filter[]:排除哪些包
//@ComponentScan includeFilters = ComponentScan.Filter[]:只要哪些包
//FilterType.ANNOTATION:按照注解
//FilterType.ASSIGNABLE_TYPE:按照给定类型
//FilterType.ASPECTJ:按照ASPECTJ表达式
//FilterType.REGEX:按照正则表达式
//FilterType.CUSTOM:按照自定义规则
@ComponentScans(
        value = {
                @ComponentScan(
                        value = {"bean", "config", "controller", "dao", "service"},
                        includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})},
                        useDefaultFilters = false
                        //excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})}
                )
        }
)
public class MainConfig {

    //给容器中注册一个Bean;类型为返回值类型,id默认是用方法名作为id
    @Bean("person") //可以传入参数,作为id
    public Person person01(){
        return new Person("lisi", 20);
    }


}
--->bean.Person
--->config.MyTypeFilter
--->controller.BookController
--->dao.BookDao
--->service.BookService
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
person
myTypeFilter
bookController
bookService

4、使用@Scope注解设置组件的作用域

创建一个配置类MainConfig2:

@Configuration
public class MainConfig2 {

    //默认是单实例
    @Bean("person")
    public Person person(){
        return new Person("张三", 5);
    }
}

默认情况下是**单实例的,即不管多少次getBean()**,获取到的都是那一个new Person("张三", 5):

@Test
public void test4(){
    ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
    String[] definitionNames = applicationContext.getBeanDefinitionNames();
    
    //默认是单实例
    Object bean = applicationContext.getBean("person");
    Object bean2 = applicationContext.getBean("person");
    System.out.println(bean == bean2); //true
}

可以使用@Scope注解为其配置实现单实例还是多实例,查看@Scope源码:

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@documented
public @interface Scope {

   @AliasFor("scopeName")
   String value() default "";

   	
	@AliasFor("value")
	String scopeName() default "";

   ScopedProxyMode proxyMode() default ScopedProxyMode.DEFAULT;

}

发现有四个取值:

    ConfigurableBeanFactory.SCOPE_PROTOTYPE, prototype:多实例ConfigurableBeanFactory.SCOPE_SINGLETON, singleton:单实例(默认值)org.springframework.web.context.WebApplicationContext.SCOPE_REQUEST, request:同一个请求创建一个实例org.springframework.web.context.WebApplicationContext.SCOPE_SESSION, session:同一个session创建一个实例
@Configuration
public class MainConfig2 {

    //默认是单实例

    
    @Scope("prototype")
    @Bean("person")
    public Person person(){
        return new Person("张三", 5);
    }
}
@Test
public void test4(){
    ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
    String[] definitionNames = applicationContext.getBeanDefinitionNames();

    //默认是单实例
    Object bean = applicationContext.getBean("person");
    Object bean2 = applicationContext.getBean("person");
    System.out.println(bean);
    System.out.println(bean2);
    
    System.out.println(bean == bean2); //false
}
Person{name='张三', age=5}
Person{name='张三', age=5}
false

在xml配置文件中可以使用标签中的scope属性实现:


    
    

4.1、单实例和多实例情况下,对象是何时创建的?

先来看单实例情况,在return new Person("张三", 5);调用创建对象的方法之前添加一个System.out.println("给容器中添加Pserson...");语句:

@Configuration
public class MainConfig2 {

    //默认是单实例

    
    @Scope //调整作用域
    @Bean("person")
    public Person person(){
        System.out.println("给容器中添加Pserson...");
        return new Person("张三", 5);
    }
}

在测试代码中,先来创建IOC容器,并没有从容器中拿出对象:

@Test
public void test4(){
    ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
    //String[] definitionNames = applicationContext.getBeanDefinitionNames();
    //
    //默认是单实例
    System.out.println("IOC容器创建完成");
    //Object bean = applicationContext.getBean("person");
    //Object bean2 = applicationContext.getBean("person");
    //System.out.println(bean);
    //System.out.println(bean2);

    //System.out.println(bean == bean2);
}
给容器中添加Pserson...
IOC容器创建完成

打印出给容器中添加Pserson...。因此,可以推断:单实例(默认值),IOC容器启动时会调用方法创建对象,并放到IOC容器中。以后每次获取就从容器中拿,因此是单实例。

再看多实例情况:

@Configuration
public class MainConfig2 {

    //默认是单实例

    
    @Scope("prototype") //调整作用域
    @Bean("person")
    public Person person(){
        System.out.println("给容器中添加Pserson...");
        return new Person("张三", 5);
    }
}

依然只创建IOC容器:

@Test
public void test4(){
    ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
    //String[] definitionNames = applicationContext.getBeanDefinitionNames();
    //
    //默认是单实例
    //System.out.println("IOC容器创建完成");
    //Object bean = applicationContext.getBean("person");
    //Object bean2 = applicationContext.getBean("person");
    //System.out.println(bean);
    //System.out.println(bean2);

    //System.out.println(bean == bean2);
}

并没有任何输出。因此可以推断:多实例,创建IOC 容器时,并不会创建对象

开启获取对象,在获取对象前添加System.out.println("IOC容器创建完成");:

@Test
public void test4(){
    ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
    //String[] definitionNames = applicationContext.getBeanDefinitionNames();
    //
    //默认是单实例
    System.out.println("IOC容器创建完成");
    Object bean = applicationContext.getBean("person");
    Object bean2 = applicationContext.getBean("person");
    //System.out.println(bean);
    //System.out.println(bean2);

    //System.out.println(bean == bean2);
}
IOC容器创建完成
给容器中添加Pserson...
给容器中添加Pserson...

获取了两次对象,输出了两次给容器中添加Pserson...。因此,可以推断:多实例,IOC容器启动并不会调用方法创建对象放到IOC容器中,以后每次获取时才会调用方法创建对象


5、@Lazy-bean如何实现懒加载?

懒加载是针对单实例bean:

单实例bean默认在容器启动时创建对象;懒加载:容器启动时不创建对象,第一次使用(获取)bean时创建对象,并初始化。

@Scope//("prototype") //调整作用域
@Lazy //懒加载
@Bean("person")
public Person person(){
    System.out.println("给容器中添加Pserson...");
    return new Person("张三", 5);
}

测试时,先不获取对象:

@Test
public void test4(){
    ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
    //String[] definitionNames = applicationContext.getBeanDefinitionNames();
    //
    //默认是单实例
    System.out.println("IOC容器创建完成");
    //Object bean = applicationContext.getBean("person");
    //Object bean2 = applicationContext.getBean("person");
    //System.out.println(bean);
    //System.out.println(bean2);

    //System.out.println(bean == bean2);
}
IOC容器创建完成

只打印出IOC容器创建完成。并没创建对象。

获取对象,并判断对象是否相等:

@Test
public void test4(){
    ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
    //String[] definitionNames = applicationContext.getBeanDefinitionNames();
    //
    //默认是单实例
    System.out.println("IOC容器创建完成");
    Object bean = applicationContext.getBean("person");
    Object bean2 = applicationContext.getBean("person");
    System.out.println(bean);
    System.out.println(bean2);

    System.out.println(bean == bean2);
}
IOC容器创建完成
给容器中添加Pserson...
Person{name='张三', age=5}
Person{name='张三', age=5}
true

可以看到,虽然获取了两次对象,但只打印了一次给容器中添加Pserson...,说明只调用了一次创建对象的方法,因此,两个对象相等。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/785164.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号