Spring 注解

相关依赖:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.0.6.RELEASE</version>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
</dependency>

配置文件方式:

使用xml方式配置bean到IOC容器中

<?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.lb.spring.day1.part1.Person">
		<property name="name" value="lb"></property>
		<property name="age" value="19"></property>
	</bean>
</beans>
public class BeanTest {
    public static void main(String[] args) {
        ApplicationContext app = new ClassPathXmlApplicationContext("beans.xml");
        Person person = (Person) app.getBean("person");
        System.out.println(person);
    }
}

结果:

Person{name='lb', aga=19}

注解方式:

@Configuration

@Configuration 等同于Spring的配置文件.

Spring注入bean的方式

  1. @Bean -- 导入第三方的类或包的组件,比如有一个第三方的类A,需要导入到IOC容器中使用
  2. 包扫描+组件的表示注解(@ComponentScan + @Controller, @Service, @Responsitory, @Component), 一般针对自己写的类,使用这个
  3. @Import:快速给容器导入一个或多个组件
    1. @Import(要导入的容器的组件):容器会自动注册这个组件,bean的id为全类名
    2. ImportSelector:是一个接口,返回需要导入到容器的组件的全类名数组
    3. ImportBeanDefinitionRegistrar:可以手动添加组件到IOC容器, 所有Bean的注册可以使用BeanDifinitionRegistry
  4. 使用Spring提供的FactoryBean(工厂bean进行注册)

 

@Bean

将Bean注入到IOC容器中

@Configuration
public class MyConfigration1 {
    @Bean //将bean注入到IOC容器中,默认为单例模式,如果不设置bean的id名称默认方法名为bean的id名称
    public Person person01(){
        Person person = new Person("lb",20);
        return person;
    }

    @Bean("myPerson") //设置了Bean的id名称
    public Person person(){
        Person person = new Person("lb",21);
        return person;
    }
}

 

public class Part2Test {
    @Test
    public void test(){
        ApplicationContext app = new AnnotationConfigApplicationContext(MyConfigration1.class);
        String[] names = app.getBeanDefinitionNames();
        for (String name : names){
            System.out.println(name);
        }
        Person person = (Person) app.getBean("person01");
        System.out.println(person);

        Person person2 = (Person) app.getBean("myPerson");
        System.out.println(person2);
    }
}

结果:

myConfigration1
person01
myPerson
Person{name='lb', aga=20}
Person{name='lb', aga=21}

Condition接口

自定义类实现Condition接口,配合@Conditional 和 @Bean使用,可以有条件的注入

/**
 * 如果系统为Windows, 则向IOC容器中注入被注解引用的类
 */
public class WinCondition implements Condition {
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        Environment environment = conditionContext.getEnvironment();
        String name = environment.getProperty("os.name");
        if (name.contains("Windows")){
            return true;
        }
        return false;
    }
}

/**
 * 如果系统为Linux, 则向IOC容器中注入被注解引用的类
 */
public class LinuxCondition implements Condition {
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        Environment environment = conditionContext.getEnvironment();
        String name = environment.getProperty("os.name");
        if (name.contains("Linux")){
            return true;
        }
        return false;
    }
}

@Configuration
public class MyConfigration6 {

    @Bean
    public Person person(){
        return new Person("person",25);
    }

    @Conditional(value = WinCondition.class)
    @Bean("lb")
    public Person lb(){
        return new Person("lb",18);
    }

    @Conditional(value = LinuxCondition.class)
    @Bean("lb2")
    public Person lb2(){
        return new Person("lb2",19);
    }
}

public class Part6Test {
    @Test
    public void test() {
        ApplicationContext app = new AnnotationConfigApplicationContext(MyConfigration6.class);
        String[] names = app.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
        System.out.println("IOC容器已经加载完成");
    }
}

接口: 测试机器系统为window7

myConfigration6
person
lb
IOC容器已经加载完成

@ComponentScan

value属性

Spring扫描包的路径

@Configuration
@ComponentScan(value = "com.lb.spring.day1.part3")
public class MyConfigration2 {
    @Bean
    public Person person(){
        Person person = new Person("lb",20);
        return person;
    }
}
@Controller
public class MyController {
}
@Repository
public class MyDao {
}
@Service
public class MyService {
}
public class Part3Test {
    @Test
    public void test(){
        ApplicationContext app = new AnnotationConfigApplicationContext(MyConfigration2.class);
        String[] names = app.getBeanDefinitionNames();
        for (String name : names){
            System.out.println(name);
        }
    }
}

结果:

myConfigration2
myController
myDao
myService
person

includeFilters属性

扫描的包中,包含哪些内容,但是必须和useDefaultFilters属性同时使用,默认为true,需要修改成false. includeFilters才能过滤成功:

@Configuration
@ComponentScan(value = "com.lb.spring.day1.part3",includeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class})
},useDefaultFilters = false)
public class MyConfigration2 {
    @Bean
    public Person person(){
        Person person = new Person("lb",20);
        return person;
    }
}

结果:

只注入了Controller注解的类

myConfigration2
myController
person

excludeFilters属性

扫描的包中,不包含哪些内容,useDefaultFilters=true

FilterType.ANNOTATION 为注解,与classes使用
FilterType.ASSIGNABLE_TYPE为具体的类,与value使用

 

@Configuration
@ComponentScan(value = "com.lb.spring.day1.part3",excludeFilters = {
        @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,value = {MyController.class})
})
public class MyConfigration2 {
    @Bean
    public Person person(){
        Person person = new Person("lb",20);
        return person;
    }
}

结果:

myConfigration2
myDao
myService
person

FileType

//FilterType.ANNOTATION:按照注解

//FilterType.ASSIGNABLE_TYPE:按照给定的类型;比如按BookService类型

//FilterType.ASPECTJ:使用ASPECTJ表达式

//FilterType.REGEX:使用正则指定

//FilterType.CUSTOM:使用自定义规则,自已写类,实现TypeFilter接口

自定义规则: implements TypeFilter

public class LbTypeFilter implements TypeFilter {
    /**
     * @param metadataReader 读取到正在扫描类的信息
     * @param metadataReaderFactory
     * @return
     * @throws IOException
     */
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        String className = classMetadata.getClassName();
        System.out.println("--------------------"+className);
        if (className.contains("controller")){
            return true;
        }
        return false;
    }
}
@Configuration
@ComponentScan(value = "com.lb.spring.day1.part3",excludeFilters = {
        @ComponentScan.Filter(type = FilterType.CUSTOM,value = {LbTypeFilter.class})
})
public class MyConfigration2 {
    @Bean
    public Person person(){
        Person person = new Person("lb",20);
        return person;
    }
}

结果:

myConfigration2
myDao
myService
person

@Import

使用@Import直接导入类

public class Dog {
}

public class Cat {
}

@Configuration
@Import(value = {Dog.class, Cat.class})
public class MyConfigration7 {
    @Bean
    public Person person(){
        return new Person("person",25);
    }
}

public class Part7Test {
    @Test
    public void test() throws Exception {
        ApplicationContext app = new AnnotationConfigApplicationContext(MyConfigration7.class);
        String[] names = app.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
    }
}

 结果:

可以发下Dog 和 Cat已经注入到Spring容器中,bean的id为类的全类名

myConfigration7
com.lb.spring.day2.part7.bean.Dog
com.lb.spring.day2.part7.bean.Cat
person

ImportSelector 接口

使用ImportSelector接口配合@Import使用,将一组bean注入到IOC容器中, 注意注入类为类的全路径

public class Fish {
}

public class Tiger {
}

public class LbImportSelector implements ImportSelector {
    /**
     * @param annotationMetadata 当前标注@Import注解类的所有注解信息,不止能获取到import注解,还能获取到其他注解
     * @return
     */
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        //批量将bean注入到IOC容器中
        return new String[]{"com.lb.spring.day2.part7.bean.Fish","com.lb.spring.day2.part7.bean.Tiger"};
    }
}

@Configuration
@Import(value = {Dog.class, Cat.class, LbImportSelector.class})
public class MyConfigration7 {
    @Bean
    public Person person(){
        return new Person("person",25);
    }
}

 结果:

Fish 和 Tiger已经注入到IOC容器中,并且bean 的 id是全类名

myConfigration7
com.lb.spring.day2.part7.bean.Dog
com.lb.spring.day2.part7.bean.Cat
com.lb.spring.day2.part7.bean.Fish
com.lb.spring.day2.part7.bean.Tiger
person

 ImportBeanDefinitionRegistrar接口

使用ImportBeanDefinitionRegistrar接口配合@Import,可以将多个Bean加入到IOC容器中,并且可以设置bean的id

public class Pig {
}

public class LbImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    /**
     * @param annotationMetadata 当前类的注解信息
     * @param beanDefinitionRegistry BeanDefinitionz注册类 把所有需要添加到容器中的bean调用registerBeanDefinition自定义手工注册到IOC容器中
     */
    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
        boolean dogFlag = beanDefinitionRegistry.containsBeanDefinition("com.lb.spring.day2.part7.bean.Dog");
        boolean catFlag = beanDefinitionRegistry.containsBeanDefinition("com.lb.spring.day2.part7.bean.Cat");
        if (dogFlag && catFlag){//如果IOC容器中已经注入了Dog和Cat
            RootBeanDefinition beanDefinition = new RootBeanDefinition(Pig.class);
            beanDefinitionRegistry.registerBeanDefinition("pig",beanDefinition);
        }
    }
}

@Configuration
@Import(value = {Dog.class, Cat.class, LbImportSelector.class, LbImportBeanDefinitionRegistrar.class})
public class MyConfigration7 {
    @Bean
    public Person person(){
        return new Person("person",25);
    }
}

结果:

在自定义的ImportBeanDefinitionRegistrar中判断容器中是否已经存在Dog和Cat,如果存在则将Pig加入到IOC容器中,bean的id为pig

myConfigration7
com.lb.spring.day2.part7.bean.Dog
com.lb.spring.day2.part7.bean.Cat
com.lb.spring.day2.part7.bean.Fish
com.lb.spring.day2.part7.bean.Tiger
person
pig

 自定义FactoryBean

通过实现的FactoryBean接口,往IOC容器中注册类

public class Monkey {
    private String name;

    public Monkey() {
    }

    public Monkey(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

public class LbBeanFactory implements FactoryBean<Monkey> {
    public Monkey getObject() throws Exception {
        return new Monkey("taotao");
    }

    public Class<?> getObjectType() {
        return Monkey.class;
    }

    public boolean isSingleton() {
        return false;
    }
}

@Configuration
@Import(value = {Dog.class, Cat.class, LbImportSelector.class, LbImportBeanDefinitionRegistrar.class})
public class MyConfigration7 {
    @Bean
    public Person person(){
        return new Person("person",25);
    }
    @Bean
    public LbBeanFactory lbBeanFactory(){
        return new LbBeanFactory();
    }
}

public class Part7Test {
    @Test
    public void test() throws Exception {
        ApplicationContext app = new AnnotationConfigApplicationContext(MyConfigration7.class);
        String[] names = app.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
        //获取BeanFactory 注入的对象
        Monkey monkey = (Monkey) app.getBean("lbBeanFactory");
        System.out.println(monkey.getClass().getName());
        System.out.println(monkey.getName());
        System.out.println("---------------------------");
        //获取LbBeanFactory本身对象
        LbBeanFactory lbBeanFactory = (LbBeanFactory) app.getBean("&lbBeanFactory");
        System.out.println(lbBeanFactory.getClass().getName());
        System.out.println("IOC容器已经加载完成");
    }
}

结果:

可以从容器中得到id为lbBeanFactory的Moneky实例,并且通过id="&lbBeanFactory"可以从容器中得到自定义BeanFactory(LbBeanFactory)的实例

myConfigration7
com.lb.spring.day2.part7.bean.Dog
com.lb.spring.day2.part7.bean.Cat
com.lb.spring.day2.part7.bean.Fish
com.lb.spring.day2.part7.bean.Tiger
person
lbBeanFactory
pig
com.lb.spring.day2.part7.bean.Monkey
taotao
---------------------------
com.lb.spring.day2.part7.LbBeanFactory
IOC容器已经加载完成

@Scope

 //给容器中注册一个bean, 类型为返回值的类型, 默认是单实例
    /*
     * prototype:多实例: IOC容器启动的时候,IOC容器启动并不会去调用方法创建对象, 而是每次获取的时候才会调用方法创建对象
     * singleton:单实例(默认):IOC容器启动的时候会调用方法创建对象并放到IOC容器中,以后每次获取的就是直接从容器中拿同一个bean
     * request: 主要针对web应用, 递交一次请求创建一个实例
     * session:同一个session创建一个实例
     */

默认配置:单例

@Configuration
public class MyConfigration3 {
    @Scope
    @Bean
    public Person person(){
        Person person = new Person("lb",20);
        return person;
    }
}

public class Part4Test {
    @Test
    public void test() {
        ApplicationContext app = new AnnotationConfigApplicationContext(MyConfigration3.class);
        String[] names = app.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
        Person person = (Person) app.getBean("person");
        Person person2 = (Person) app.getBean("person");
        System.out.println(person == person2);
    }
}

结果:

myConfigration3
person
true

多实例:

@Configuration
public class MyConfigration3 {
    @Scope("prototype")
    @Bean
    public Person person(){
        Person person = new Person("lb",20);
        return person;
    }
}

public class Part4Test {
    @Test
    public void test() {
        ApplicationContext app = new AnnotationConfigApplicationContext(MyConfigration3.class);
        String[] names = app.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
        Person person = (Person) app.getBean("person");
        Person person2 = (Person) app.getBean("person");
        System.out.println(person == person2);
    }
}

结果:

myConfigration3
person
false

@Lazy

延迟加载,一般的Bean在spring容器初始化时会加载到容器中,但是使用@Lazy在容器启动时不会立刻实例化,只有再被调用的时候才会被实例化到容器中

在不使用@Lazy时:

@Configuration
public class MyConfigration4 {

    @Bean
    public Person person(){
        Person person = new Person("lb",25);
        System.out.println("Person add to IOC");
        return person;
    }
}

public class Part5Test {
    @Test
    public void test() {
        ApplicationContext app = new AnnotationConfigApplicationContext(MyConfigration4.class);
        String[] names = app.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
        System.out.println("IOC容器已经加载完成");
        Person person = (Person) app.getBean("person");
        System.out.println(person);
    }
}

结果:

在容器初始化时已经将Person注入到容器中

Person add to IOC
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
myConfigration4
person
IOC容器已经加载完成
Person{name='lb', aga=25}

使用@Lazy:

@Configuration
public class MyConfigration4 {

    @Lazy
    @Bean
    public Person person(){
        Person person = new Person("lb",25);
        System.out.println("Person add to IOC");
        return person;
    }
}

public class Part5Test {
    @Test
    public void test() {
        ApplicationContext app = new AnnotationConfigApplicationContext(MyConfigration4.class);
        String[] names = app.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
        System.out.println("IOC容器已经加载完成");
        Person person = (Person) app.getBean("person");
        System.out.println(person);
    }
}

结果:

容器先初始化成功,在调用时才将Person添加到IOC 容器中

myConfigration4
person
IOC容器已经加载完成
Person add to IOC
Person{name='lb', aga=25}

@Value

使用@Value给类的属性赋值

  1. 直接赋值基本字符 : wangcai
  2. 使用SpringEL表达式:#{10-5} 等等
  3. 读取配置文件中的值: ${xxx.xxx},  //读取到的值被存储在环境变量中
@Configuration
//使用@PropertySource进行配置文件的读取,可以读取多个文件
@PropertySource(value = {"classpath:/test.properties"})
public class MyConfigration13 {
    @Bean
    public Dog dog(){
        return new Dog();
    }
}

public class Dog {
    //直接赋值字符串
    @Value("wangcai")
    private String name;
    //使用SpringEL表达式赋值
    @Value("#{10-5}")
    private Integer age;
    //从配置文件中读取
    @Value("${dog.color}")
    private String color;

    public Dog() {
    }

    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 String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", color='" + color + '\'' +
                '}';
    }
}

public class Part13Test {
    @Test
    public void test() throws Exception {
        AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(MyConfigration13.class);
        String[] names = app.getBeanDefinitionNames();
        for (String name : names){
            System.out.println(name);
        }
        Dog dog = (Dog) app.getBean("dog");
        System.out.println(dog);
        ConfigurableEnvironment environment = app.getEnvironment();
        //Spring读取的配置文件信息,存储在环境变量中
        System.out.println("environment--->"+environment.getProperty("dog.color")); 
        System.out.println("IOC 容器初始化完成....");
    }
}

 结果:

根据@ValueDog属性分别赋值,使用@PropertySource读取配置文件

myConfigration13
dog
Dog{name='wangcai', age=5, color='yellow'}
environment--->yellow
IOC 容器初始化完成....

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值