Spring注解开发

目录

@Configuration

@Bean

@ComponentScan

@Scope

@Lazy

@Conditional

@PropertySource

@Value

@Autowired & @Qualifier & @Primary 与 @Resource,@Inject


@Configuration

告诉spring这是一个配置类,配置类 = 配置文件

@Configuration
public class MainConfig {
}

@Bean

给容器注入一个bean

1).bean的类型为返回值类型,bean的名称默认是方法名

2).可以自定义bean的名称:@Bean("person")

3).下面的例子中,给容器MainConfig 注入一个Person,自定义名称为person

@Configuration
public class MainConfig {
    @Bean("person") //自定义bean的名称为person
    public Person person01() {
        return new Person("lbl",35);
    }
}
    @Test
    public void test() {
        ApplicationContext app = new AnnotationConfigApplicationContext(MainConfig.class);
        Arrays.stream(app.getBeanDefinitionNames()).forEach(System.out::println);
    }

输入结果:

mainConfig   
person

----------------------------------------------

小提示:@Configuratiion标注的配置类同时也是一个组件(@Configuratiion里面标注了@Component),所以也在输出结果中.

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
    String value() default "";
}

@ComponentScan

定义扫描规则

例子:

@Configuration
@ComponentScan(value = "com.atguigu", useDefaultFilters = false,
        includeFilters = {
//            @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class,Repository.class}),
//                @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {BookService.class}),
                @ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyFilterType.class})
        }
)
public class MainConfig {
    @Bean("person") 
    public Person person01() {
        return new Person("lbl",35);
    }
}

@ComponentScan的属性说明

属性返回类型说明
valueString[]指定要扫描的包
useDefaultFiltersboolean指定过滤规则,默认的过滤规则是扫描所有(即会把标注了@Controller,@Service,@Repository,@Component 等等全部扫描),所以一般是设置为false
excludeFiltersFilter[]指定扫描的时候按照什么规则排除那些组件
includeFiltersFilter[]指定扫描的时候只需要包含哪些组件

 

 

 

 

 

 

Filter[]类型和说明

类型说明
FilterType.ANNOTATION按照注解
FilterType.ASSIGNABLE_TYPE按照给定的类型
FilterType.ASPECTJ使用aspectj表达式
FilterType.REGEX使用正则
FilterType.CUSTOM使用自定义规则 (当前扫描包下的所有类都会进行匹配)

 

 

 

 

 

 

 

自定义TypeFilter指定过滤规则

自定义的类实现TypeFilter,重写match方法,在里面自定义过滤规则。

例子:

import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;
import java.io.IOException;

public class MyFilterType implements TypeFilter {

    //metadataReader: 读取到当前正在扫描的类的信息
    //metadataReaderFactory:可以获取到其他任何的类的信息
    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        //获取当前类注解的信息
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        //获取当前正在扫描的类的类信息(比如类的类型是什么,实现什么接口)
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        String className = classMetadata.getClassName();
        //获取当前类资源(类的路径)
        Resource resource = metadataReader.getResource();

        //自定义过滤规则
        if (className.contains("BookDao")) {
            return true;
        }
        return false;
    }
}

另外:

java8中,@ComponentScan是一个重复注解,可以写多个,定义多种扫描策略;

也可以使用@ComponentScans,里面是ComponentScan数组, 这样也可以定义多个扫描规则。

 

@Scope

设置组件作用域

singleton: 单例的(默认值)。ioc容器启动会调用方法创建对象放到ioc容器中,以后每次获取就是直接从容器中拿

prototype:多实例的。ioc容器启动并不会去调用方法创建对象放在容器中,每次获取的时候才会调用方法创建对象

request: 同一次请求创建一个实例

session: 同一个session创建一个实例

例子:

    @Scope("prototype")
    @Bean("person")
    public Person person01() {
        return new Person("lbl",35);
    }

 

@Lazy

懒加载

单实例bean:默认在容器启动的时候创建对象;

加上@Lazy:容器启动不创建对象。第一次使用(获取)Bean创建对象,并初始化;

例子:

	@Lazy
	@Bean("person")
	public Person person(){
		return new Person("lbl", 35);
	}

 

@Conditional

按照条件注册bean

@Conditional 放在类上,表示满足当前条件,这个类上配置的所有bean注册才能生效。

例子:

判断当前操作系统是linux才把名称为linus的Person注册到容器中。

@Bean("linus")
@Conditional(LinuxCondition.class)
public Person person02(){
    return new Person("linus", 48);
}

自定义的LinuxCondition类实现Condition

import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;
import java.util.Arrays;


public class LinuxCondition implements Condition {
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        Environment env = conditionContext.getEnvironment();
       //获取操作系统名称
        String osName = env.getProperty("os.name");
        if (osName.contains("linux")) {
            return true;
        }
        return false;
    }
}

@PropertySource

读取外部配置文件中的key/value,保存到运行的环境变量中

例子:

@Configuration
@PropertySource("classpath:conf/person.properties")
public class MainConfigOfPropertyValue {
    @Bean
    public Person person() {
        return new Person();
    }

}

@Value

属性赋值

方式:

1).基本数值

2).SpEl(Spring表达式):#{}

3).取配置文件的值:${} (在运行环境变量里面的值)

例子:@Value("${des}") 中的des为person.properties配置文件中的key

import org.springframework.beans.factory.annotation.Value;
public class Person {
    @Value("勒布朗")
    private String name;
    @Value("#{25-2}")
    private int age;
    @Value("${des}")
    private String des;
}

 

@Autowired & @Qualifier & @Primary 与 @Resource,@Inject

 

@Autowired: 自动注入

a.默认是优先按照类型去容器中找对应的组件

例子:

使用@Repository向容器中注入BookDao,名称为bookDao,

使用@Autowired在bookService中自动注入BookDao,名称为bookDao3,

输出bookService中的bookDao和根据类型获取的bookDao,结果一样,说明是优先按照类型去容器中找对应的组件。

@Configuration
@ComponentScan({"com.atguigu"})
public class MainConifgOfAutowired {
}
@Repository("bookDao")
public class BookDao {

}
@Service
public class BookService {
    @Autowired
    private BookDao bookDao3;

    public void print(){
        System.out.println(bookDao3);
    } 

}
    @Test
    public void test5() {
        AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(MainConifgOfAutowired.class);
        BookService bookService = app.getBean(BookService.class);
        bookService.print();
        BookDao bookDao = app.getBean(BookDao.class);
        System.out.println(bookDao);
    }

输出结果:

com.atguigu.dao.BookDao@2ea227af
com.atguigu.dao.BookDao@2ea227af

------------------------------------------------------------

b.若找到多个相同类型的组件,再将属性的名称作为组件的id去容器中查找。

例子:

使用@Repository向容器中注入一个BookDao,名称为bookDao,属性label值为1,

使用@Bean向容器中注入一个BookDao,名称为bookDao2,属性label值为2,

向BookService中注入BookDao,名称为bookDao,

输出bookService中的bookDao,结果label值为1,说明获取的是名称为bookDao的bean,

说明相同类型时,再根据名称去容器中查找。

 

@Configuration
@ComponentScan({"com.atguigu"})
public class MainConifgOfAutowired {
	@Bean("bookDao2")
	public BookDao bookDao(){
		BookDao bookDao = new BookDao();
		bookDao.setLabel("2");
		return bookDao;
	}
}
@Service
public class BookService {
    @Autowired
    private BookDao bookDao;

    public void print(){
        System.out.println(bookDao);
    }
}
@Repository("bookDao")
public class BookDao {
    private String label = "1";

    public String getLabel() {
        return label;
    }

    public void setLabel(String label) {
        this.label = label;
    }

    @Override
    public String toString() {
        return "BookDao{" + "label='" + label + '\'' + '}';
    }
}
    @Test
    public void test5() {
        AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(MainConifgOfAutowired.class);
        BookService bookService = app.getBean(BookService.class);
        bookService.print();
    }

输出结果:

BookDao{label='1'}

-----------------------------------------------------

若把BookService中的BookDao改为
    @Autowired
    private BookDao bookDao2;

输出结果为:BookDao{label='2'}

-----------------------------------------------------

c.@Autowired 默认是一定要装配成功的,否则报错。

可以通过required=false更改为  有就装配,没有也行:@Autowired(required=false)

 

@Qualifier: 明确指定要装配的组件id,而不是使用属性名

例子:虽然注入的bean名称为bookDao2,但明确指定使用bookDao

    @Qualifier("bookDao")
    @Autowired
    private BookDao bookDao2;

@Primary:让Spring进行自动装配时,默认使用首选的bean

例子:当不使用@Qualifier明确指定时,可以使用@Primary标注在某个bean上,这样默认就会使用该bean

import com.atguigu.dao.BookDao;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
@Configuration
@ComponentScan({"com.atguigu"})
public class MainConfigOfAutowired {
	@Primary
	@Bean("bookDao2")
	public BookDao bookDao(){
		BookDao bookDao = new BookDao();
		bookDao.setLabel("2");
		return bookDao;
	}
}
@Service
public class BookService {
    @Autowired
    private BookDao bookDao;

    public void print(){
        System.out.println(bookDao);
    }

    @Override
    public String toString() {
        return "BookService [bookDao=" + bookDao + "]";
    }

}
@Repository("bookDao")
public class BookDao {

    private String label = "1";

    public String getLabel() {
        return label;
    }

    public void setLabel(String label) {
        this.label = label;
    }

    @Override
    public String toString() {
        return "BookDao{" + "label='" + label + '\'' + '}';
    }
}
    @Test
    public void test5() {
        AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(MainConfigOfAutowired.class);
        BookService bookService = app.getBean(BookService.class);
        bookService.print();
    }

输出结果:

BookDao{label='2'}

----------------------------------------------

@Resource

它不是Spring的注解,是java规范中的,是JSR250定义的注解(JSR是Java Specification Requests——java 规范要求)可以和@Autowired一样实现自动装配功能;默认是按照组件名称进行装配的,也可以指定名称:

@Resource(name="bookDao");
private BookDao bookDao3;

但没有@Primary功能,也没有@Autowired(reqiured=false),即一定要装配上,否则报错。

 

注意:

此处说没有@Primary功能,是说当@Resource标注的bean装配上时,另外一个同样类型的bean标注了@Primary也不会使用;

但当@Resource标注的bean装配不上时,另外一个同样类型且标注了@Primary的bean则可以装配上。

例如:

容器里有bookDao 和 bookDao2,

当使用

@Resource
private BookDao bookDao;

 

	@Primary
	@Bean("bookDao2")
	public BookDao bookDao(){
		BookDao bookDao = new BookDao();
		bookDao.setLabel("2");
		return bookDao;
	}

装配的是bookDao,说明@Primary不起作用;

但当

@Resource
private BookDao bookDao3;

 

	@Primary
	@Bean("bookDao2")
	public BookDao bookDao(){
		BookDao bookDao = new BookDao();
		bookDao.setLabel("2");
		return bookDao;
	}

装配的是bookDao2,说明@Primary起作用了;若没@Primary,则会找不到,报错。

 

@Inject

是JSR330定义的注解,需要导入javax.inject的包,依赖为:

<dependency>
   <groupId>javax.inject</groupId>
   <artifactId>javax.inject</artifactId>
   <version>1</version>
</dependency>

和Autowired一样可以实现自动装配功能。若想指定名称,使用@Named

    @Inject
    @Named("bookDao")
    private BookDao bookDao3;

但没有@Primary功能,也没有@Autowired(reqiured=false)。

注意:此处说没有@Primary功能,和@Resource的情况一样。

 

另外:

@Autowired不仅作用在属性上,还可以作用在 构造器,参数,方法 上,作用都是从容器中获取参数组件的值。

标注在方法上:

    @Autowired //方法参数的值从ioc容器中获取
    public void setCourse(Course course) {
        this.course = course;
    }

@Bean+方法参数;参数从容器中获取;默认不写@Autowired效果是一样的,都能自动装配;

    @Bean
    public Student student(@Autowired Course course) { //这里写不写@Autowired都可以
        return new Student(course);
    }

标注在构造器上:如果组件只有一个有参构造器,这个有参构造器的@Autowired可以省略,参数位置的组件还是可以自动从容器中获取。

    @Autowired //这里写不写@Autowired都可以
    public Student(Course course) {
        this.course = course;
    }

 

标注在参数上:

    public void setCourse(@Autowired Course course) {
        this.course = course;
    }

// =================或者========================

    public Student(@Autowired Course course) {
        this.course = course;
    }

 

综上:自动注入时,推荐使用@AutoWired

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值