Spring IoC注解式开发

Spring IoC注解式开发


一、声明Bean的注解

  • 负责声明 Bean(xml配置中的bean标签的作用是一样的) 的注解,常见的包括四个:
    • @Component
    • @Controller 控制器类上使用
    • @Service service类上使用
    • @Repository dao类上使用
  • @Controller@Service@Repository这三个注解都是@Component注解的别名。也就是说:这四个注解的功能都一样。用哪个都可以。只是为了增强程序的可读性。
  • 他们都是只有一个value属性。value属性用来指定bean的id,也就是bean的名字。

1.@Component

java 复制代码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface Component {
	String value() default "";
}

2.@Controller

java 复制代码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
	@AliasFor(annotation = Component.class)
	String value() default "";
}

3.@Service

java 复制代码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {
	@AliasFor(annotation = Component.class)
	String value() default "";
}

4.@Repository

java 复制代码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Repository {
	@AliasFor(annotation = Component.class)
	String value() default "";
}

二、Spring注解的使用

  • 如何使用以上的注解呢?

    • 第一步:加入aop的依赖
      • 当加入spring-context依赖之后,会关联加入aop的依赖。
    • 第二步:在配置文件中添加context命名空间
    xml 复制代码
    <?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"
           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.xsd">
    </beans>
    • 第三步:在配置文件中指定扫描的包
      • 如果是多个包怎么办,有两种解决方案:
        • 第一种:在配置文件中指定多个包,用逗号隔开。
        • 第二种:指定多个包的共同父包。
    xml 复制代码
    <?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"
           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.xsd">
        <context:component-scan base-package="com.powernode.spring6.bean"/>
    </beans>
    • 第四步:在Bean类上使用注解
      • 注解的属性名是value,那么value是可以省略的。
      • 如果把value属性彻底去掉,spring会为Bean自动取名,并且默认名字的规律是:Bean类名首字母小写即可。
    java 复制代码
    package com.gdb.spring6.bean;
    
    import org.springframework.stereotype.Component;
    
    //@Component(value = "userBean")和下面的效果是一样的
    @Component 
    public class User {
    }

三、选择性实例化Bean

  • 假设在某个包下有很多Bean,有的Bean上标注了Component,有的标注了Controller,有的标注了Service,有的标注了Repository,现在由于某种特殊业务的需要,只允许其中所有的Controller参与Bean管理,其他的都不实例化。这应该怎么办呢?

    xml 复制代码
    <?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"
           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.xsd">
    	<!-- 
    		use-default-filters="true" (默认值)表示:使用spring默认的规则,只要有Component、Controller、Service、Repository中的任意一个注解标注,则进行实例化。
    		use-default-filters="false" 表示:不再spring默认实例化规则,即使有Component、Controller、Service、Repository这些注解标注,也不再实例化。
    	 -->
        <context:component-scan base-package="com.gdb.spring6.bean3" use-default-filters="false">
            <!-- 表示只有Controller进行实例化。 -->
            <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
        </context:component-scan>
    </beans>
    xml 复制代码
    <!-- 也可以将use-default-filters设置为true(不写就是true),并且采用exclude-filter方式排出哪些注解标注的Bean不参与实例化: -->
    <context:component-scan base-package="com.powernode.spring6.bean3">
      <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
      <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
      <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

四、负责注入的注解

  • @Component@Controller @Service @Repository 这四个注解是用来声明Bean的,声明后这些Bean将被实例化。接下来我们看一下,如何给Bean的属性赋值。给Bean属性赋值需要用到这些注解:

1.@Value

java 复制代码
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Value {
	String value();
}
  • 当属性的类型是简单类型时,可以使用@Value注解进行注入。
  • 注解 @Value的语法格式:@Value(${"key:默认值"})

2.@Autowired和@Qualifier

java 复制代码
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
	boolean required() default true;
}
java 复制代码
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Qualifier {
	String value() default "";
}
  • @Autowired注解有一个required属性,默认值是true,表示在注入的时候要求被注入的Bean必须是存在的,如果不存在则报错。如果required属性设置为false,表示注入的Bean存在或者不存在都没关系,存在的话就注入,不存在的话,也不报错。
  • @Autowired注解可以用来注入非简单类型。单独使用@Autowired注解,默认根据类型装配。【默认是byType】
  • @Autowired注解和@Qualifier注解联合起来才可以根据名称进行装配,在@Qualifier注解中指定Bean名称。

3.@Resource

java 复制代码
@Target({TYPE, FIELD, METHOD})
@Retention(RUNTIME)
@Repeatable(Resources.class)
public @interface Resource {
    String name() default "";
    String lookup() default "";
    Class<?> type() default java.lang.Object.class;
    enum AuthenticationType {
	    CONTAINER,
	    APPLICATION
    }
    AuthenticationType authenticationType() default AuthenticationType.CONTAINER;
    boolean shareable() default true;
    String mappedName() default "";
    String description() default "";
}
  • @Resource注解也可以完成非简单类型注入。那它和@Autowired注解有什么区别?

    • @Resource注解是JDK扩展包中的,也就是说属于JDK的一部分。所以该注解是标准注解,更加具有通用性。(JSR-250标准中制定的注解类型。JSR是Java规范提案。)
    • @Autowired注解是Spring框架自己的。
    • @Resource注解默认根据名称装配byName,未指定name时,使用属性名作为name。通过name找不到的话会自动启动通过类型byType装配。
    • @Autowired注解默认根据类型装配byType,如果想根据名称装配,需要配合@Qualifier注解一起用。
  • @Resource注解属于JDK扩展包,所以不在JDK当中,需要额外引入以下依赖:【如果是JDK8的话不需要额外引入依赖。高于JDK11或低于JDK8需要引入以下依赖。】

    xml 复制代码
    <dependency>
      <groupId>jakarta.annotation</groupId>
      <artifactId>jakarta.annotation-api</artifactId>
      <version>2.1.1</version>
    </dependency>

五、全注解式开发

  • 所谓的全注解开发就是不再使用spring配置文件了。写一个配置类来代替配置文件

    java 复制代码
    package com.gdb.spring6.config;
    
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.ComponentScans;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    @ComponentScan({"com.gdb.spring6.dao", "com.gdb.spring6.service"})
    public class Spring6Configuration {
    }
  • 编写测试程序:不再new ClassPathXmlApplicationContext()对象了。

    java 复制代码
    @Test
    public void testNoXml(){
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Spring6Configuration.class);
        UserService userService = applicationContext.getBean("userService", UserService.class);
        userService.save();
    }

1.@Configuration

java 复制代码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
	@AliasFor(annotation = Component.class)
	String value() default "";
	boolean proxyBeanMethods() default true;
	boolean enforceUniqueMethods() default true;
}
  • 注意:@Configuration包含有@Component注解的功能。
  • @Configuration注解用于标识一个类作为配置类(可以代替XML配置文件),它通常与@Bean注解一起使用。配置类是Spring IoC容器的一部分,它定义了一组Bean的创建和配置规则。

2.@Bean

java 复制代码
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {
	@AliasFor("name")
	String[] value() default {};
	@AliasFor("value")
	String[] name() default {};
	boolean autowireCandidate() default true;
	String initMethod() default "";
	String destroyMethod() default AbstractBeanDefinition.INFER_METHOD;
}
  • Spring的@Bean注解用于告诉方法,产生一个Bean对象,然后这个Bean对象交给Spring管理。 产生这个Bean对象的方法Spring只会调用一次,随后这个Spring将会将这个Bean对象放在自己的IOC容器中。
  • @Component , @Repository , @ Controller , @Service 这些注解只局限于自己编写的类,而@Bean注解能把第三方库中的类实例加入IOC容器中并交给spring管理。
  • @Bean注解和xml配置中的bean标签的作用是一样的。

3.@ComponentScan

java 复制代码
@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 ClassPathScanningCandidateComponentProvider.DEFAULT_RESOURCE_PATTERN;
	boolean useDefaultFilters() default true;
	Filter[] includeFilters() default {};
	Filter[] excludeFilters() default {};
	boolean lazyInit() default false;
	@Retention(RetentionPolicy.RUNTIME)
	@Target({})
	@interface Filter {
		FilterType type() default FilterType.ANNOTATION;
		@AliasFor("classes")
		Class<?>[] value() default {};
		@AliasFor("value")
		Class<?>[] classes() default {};
		String[] pattern() default {};
	}
}
  • @ComponentScan注解顾名思义就是扫描声明了@Component注解的类,然后注入到Spring容器中的。
  • @ComponentScan注解和xml配置中的ComponentScan标签的作用是一样的。

相关推荐
什么想法都无3 分钟前
stream
java·java stream
m0_748233644 分钟前
WebService简介
java
love静思冥想5 分钟前
Stream `Collectors.toList()` 和 `Stream.toList()` 的区别(Java)
java·stream
胡西风_foxww14 分钟前
【ES6复习笔记】数值扩展(16)
前端·笔记·es6·扩展·数值
mosen86816 分钟前
uniapp中uni.scss如何引入页面内或生效
前端·uni-app·scss
白云~️16 分钟前
uniappX 移动端单行/多行文字隐藏显示省略号
开发语言·前端·javascript
沙尘暴炒饭19 分钟前
uniapp 前端解决精度丢失的问题 (后端返回分布式id)
前端·uni-app
Ch.yang24 分钟前
【Spring】 Bean 注入 HttpServletRequest 能保证线程安全的原理
java·spring·代理模式
web1508509664125 分钟前
基于Mysql、JavaScript、PHP、ajax开发的MBTI性格测试网站(前端+后端)
java
昙鱼33 分钟前
springboot创建web项目
java·前端·spring boot·后端·spring·maven