Spring 5 注解编程基础组件

配置类组件

@Configuration(把一个类作为IoC容器,它的某个方法头上如果注册了@Bean,就会作为这个Spring容器中的Bean)

 

以前我们是用xml的配置文件作为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.example.entity.Person">
        <property name="name" value="Tom"></property>
        <property name="age" value="18"></property>
    </bean>

</beans>

写一个测试类: 

        ApplicationContext appcontext = new ClassPathXmlApplicationContext("application.xml");
        Person person = (Person) appcontext.getBean("person");
        System.out.println(person);

我们便可以通过这样的方式来取到Bean。

现在有了@Configuration注解我们便可以不用再写xml:


@Configuration
public class MyConfiguration {
    
    
    //默认是类名首字母小写
    //取方法名
    //优先取@Bean注解的value
    @Bean("person2")
    public Person person(){
        return new Person("mic",18);
    }
}

 

        ApplicationContext appcontext = new AnnotationConfigApplicationContext(MyConfiguration.class);
        Person person = (Person) appcontext.getBean("person");
        System.out.println(person);

@ComponentScan(在配置类上添加@ComponentScan注解。该注解默认会扫描该类所在的包下所有的配置类,相当于xml中的<context:component-scan>)

包扫描会扫描只要标注了@Controller,@Service,@Repository,@Component这四个注解都会被扫描到容器中。

也可以自定义扫描规则

@Configuration
@ComponentScan(value = "com.example",
//指定扫描的注解       includeFilters = {@Filter(type= FilterType.ANNOTATION,value = {Controller.class})}
//指定扫描的类        includeFilters = {@Filter(type = FilterType.ASSIGNABLE_TYPE,value = {MyContorller.class})}
//自定义一个扫描规则        includeFilters = {@Filter(type = FilterType.CUSTOM,value = {MyTypeFilter.class})},
        useDefaultFilters = false
)
public class MyConfiguration {

}
public class MyTypeFilter implements TypeFilter {
    /**
     *
     * @param metadataReader 获取当前正在操作的信息
     * @param metadataReaderFactory 获取上下文中所有的信息
     * @return
     * @throws IOException
     */
    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 + "------");
        if(className.contains("er")){
            //类名包含‘er’的
            return true;
        }
        return false;
    }
}

@Scope(用户指定scope作用域)

    //prototype 原型,多例
    //singleton 单例  默认
    //request 主要应用于web模块,同一次请求只创建一个实例
    //session 主要应用于web模块,同一个session只创建一个实例
    @Scope("prototype")
    @Bean
    public Person person(){
        //IoC实例化对象的时候,并不是简单地调用我们定义的方法
        return new Person("Tom",18);
    }

@Lazy(延迟初始化)

未加@Lazy注解:

@Configuration
public class MyConfiguration {

    @Bean("person2")
    public Person person(){
        System.out.println("将对象添加到IoC容器");
        return new Person("mic",18);
    }
}
@Test
public void test(){
        ApplicationContext appcontext = new AnnotationConfigApplicationContext(MyConfiguration.class);
        System.out.println("IoC容器初始化完成");   
        appcontext.getBean("person2");

}

运行结果:

加上@Lazy注解运行结果:

默认非延迟加载
懒加载只针对单例Bean起作用
默认容器启动时不创建对象,调用对象的功能时才创建

@Conditional(Spring 4开始提供,按照一定条件进行判断,满足条件给容器注册Bean)

假设:
如果操作系统是Windows,那么就将James实例化到容器中
如果操作系统是Linux,那么就将Tom实例化到容器中

@Configuration
public class MyConfig {

    @Conditional(WinCondition.class)
    @Bean
    public Person mic(){
        System.out.println("将对象Mic添加到IoC容器中");
        return new Person("Mic",16);
    }

    @Conditional(WinCondition.class)
    @Bean
    public Person tom(){
        System.out.println("将对象Tom添加到IoC容器中");
        return new Person("Tom",18);
    }

    @Conditional(LinuxCondition.class)
    @Bean
    public Person james(){
        System.out.println("将对象James添加到IoC容器中");
        return new Person("James",17);
    }
}
public class WinCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        //从IoC容器中拿到已经实例化的对象
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        Environment environment = context.getEnvironment();
        String osName = environment.getProperty("os.name");
        if(osName.contains("Windows")){
            return true;
        }
        return false;
    }
}
@Test
public void test(){
     ApplicationContext app = new AnnotationConfigApplicationContext(MyConfig.class);
     System.out.println("IoC容器创建完成");

}

@Import(导入外部资源)

@Import 直接传参导入

@Import(Person.class)

ImportSelector 自定义导入规则

@Import(MyImportSelector.class)
public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{"com.gupaoedu.project.entity.Company",
                            "com.gupaoedu.project.entity.Member"};
    }
}

ImportBeanDefinitionRegistrar ,使用BeanDefinitionRegistry可以手动注入到IoC容器中

@Import(MyImportBeanDefinitionRegistrar.class)
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    /**
     *
     * @param importingClassMetadata  当前类的注解信息
     * @param registry 完成BeanDefinition的注册
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        boolean company = registry.containsBeanDefinition("com.gupaoedu.project.entity.Company");
        boolean member = registry.containsBeanDefinition("com.gupaoedu.project.entity.Member");

        if(company && member){
            BeanDefinition beanDefinition = new RootBeanDefinition(User.class);
            registry.registerBeanDefinition("user",beanDefinition);
        }
    }
}

给IoC中注册Bean的方式
1、@Bean 直接导入单个类
2、@ComponentScan 包扫描默认是扫描(@Controller、@Service、@Repository、@Component)
3、@Import 快速给容器导入组件Bean
      a. @Import 直接传参导入
      b. ImportSelector 自定义导入规则
      c.ImportBeanDefinitionRegistrar ,使用BeanDefinitionRegistry可以手动注入到IoC容器中
4、FactoryBean 把需要注入的对象封装为FactoryBean
      a、FactoryBean 负责将Bean注入到容器的Bean
      b、BeanFactory 从IoC中获得Bean对象

FactoryBean注入方式

public class MyFactoryBean implements FactoryBean<Monkey> {
    @Nullable
    @Override
    public Monkey getObject() throws Exception {
        return new Monkey();
    }

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

    @Override
    public boolean isSingleton() {
        return true;
    }
}
@Configuration
public class MyConfig {

    @Bean
    public MyFactoryBean monkey(){
        return new MyFactoryBean();
    }
}
public class MyTest {

    @Test
    public void test(){
        ApplicationContext app = new AnnotationConfigApplicationContext(MyConfig.class);

        //通过FactoryBean注入的值
        System.out.println("============" + app.getBean("monkey").getClass());
        Object monkey1 = app.getBean("monkey");
        Object monkey2 = app.getBean("monkey");
        System.out.println("是否单例:" + monkey1 == monkey2);

        //拿到构建monkey的FactoryBean
        Object monkeyFactoryBean = app.getBean("&monkey");
        System.out.println(monkeyFactoryBean);

    }

}

Bean生命周期监控
1.添加initMethod 和 destroyMethod

@Bean(initMethod = "addOil",destroyMethod = "close")

2.实现InitializingBean和DisposableBean接口

@Component
public class Train implements InitializingBean,DisposableBean {
    @Override
    public void destroy() throws Exception {
        System.out.println("火车对象销毁");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("火车对象初始化");
    }
}


3.使用@PostConstruct和@PreDestroy注解

@Component
public class AirPlane {

    public AirPlane() {
        System.out.println("调用AirPlane的构造方法");
    }

    @PostConstruct
    public void addOil(){
        System.out.println("飞机飞行前加油");
    }

    public void run(){
        System.out.println("正在空中巡航");
    }

    @PreDestroy
    public void close(){
        System.out.println("飞机落地熄火");
    }
}

4、自己写一个类,实现BeanPostProcessor接口

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization" + beanName + "," + bean);
        return bean;
    }



    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization" + beanName + "," + bean);
        return bean;
    }
}

可以针对于所有的类

 

赋值组件

@Component(泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注)

@Service(用于标注业务层组件)

@Controller(用于标注业务层组件)

@Repository(用于标注数据访问组件,即DAO组件)

@Value(普通数据类型赋值) @PropertySource(读取配置文件赋值)

@Configuration
@PropertySource("classpath:values.properties")
public class MyConfig {

    @Bean
    public Bird bird(){
        return new Bird();
    }
}
public class Bird {

    //支持的类型
    //1、基本数据类型
    //3、Spring EL表达式
    //4、通过配置文件赋值
    @Value("鹦鹉")
    private String name;
    @Value("#{8-5}")
    private int age;

    @Value("${bird.color}")
    private String color;


    public String getColor() {
        return color;
    }

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

    public Bird() {
    }

    public Bird(String name, int age) {
        this.name = name;
        this.age = age;
    }

    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 "Bird{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", color='" + color + '\'' +
                '}';
    }
}

@Autowired(默认按类型装配,如果我们想使用按名称装配,可以结合@Qualifier注解一起使用)

@Qualifier(如存在多个实例配合使用)

@Configuration
@ComponentScan({
        "com.gupaoedu.project.controller",
        "com.gupaoedu.project.service",
        "com.gupaoedu.project.dao"
            })
public class MyConfig {

    @Bean("dao")
    public MyDao dao(){
        MyDao dao = new MyDao();
        dao.setFlag("2");
        return dao;
    }
}
@Repository
public class MyDao {
    private String flag = "1";

    public void setFlag(String flag) {
        this.flag = flag;
    }

    @Override
    public String toString() {
        return "MyDao{" +
                "flag='" + flag + '\'' +
                '}';
    }
}
@Service
public class MyService {
    @Qualifier("dao")
    @Autowired
    private MyDao myDao;

    public void print(){
        System.out.println(myDao);
    }
}
public class MyTest {
    @Test
    public void test(){
        ApplicationContext app = new AnnotationConfigApplicationContext(MyConfig.class);


        MyService service = app.getBean(MyService.class);
        service.print();


    }
}

运行结果flag = 2;

@Primary(自动装配时当出现多个Bean候选者时,被注释为@Primary的Bean将作为首选者,否则抛出异常)

@Configuration
@ComponentScan({
        "com.gupaoedu.project.controller",
        "com.gupaoedu.project.service",
        "com.gupaoedu.project.dao"
            })
public class MyConfig {


    @Primary
    @Bean("myDao")
    public MyDao dao(){
        MyDao dao = new MyDao();
        dao.setFlag("9");
        return dao;
    }


    @Bean("myDao")
    public MyDao myDao(){
        MyDao dao = new MyDao();
        dao.setFlag("3");
        return dao;
    }
}

@Resource(默认按照名称装配,当找不到与名称匹配的bean才会按类型装配)

package com.gupaoedu.project.service;

import com.gupaoedu.project.dao.MyDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * Created by Tom.
 */
@Service
public class MyService {

    @Resource(name="dao")
    private MyDao myDao;

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

织入组件

ApplicationContextAware(可以通过这个上下文环境对象得到Spring容器中的Bean)

参考:https://blog.csdn.net/qq_40718168/article/details/84062429

BeandefinitionRegistryPostProcessor

参考:https://blog.csdn.net/ztchun/article/details/90814135

切面组件

@EnableTransactionManagement(添加对事务管理的支持)

@Transactional(配置声明式事务信息)

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值