Spring框架中常用的技巧及扩展点

22 篇文章 0 订阅
2 篇文章 0 订阅

欢迎光临我的博客查看最新文章: https://river106.cn

Spring是现在非常流行的轻量级Java开发框架,简化Java开发,提供了丰富的功能,工作中基本都会使用到它,如框架整合;总结下Spring中常用的使用技巧及扩展点。

1、ApplicationContextAware、EnvironmentAware

ApplicationContextAware接口定义如下:

public interface ApplicationContextAware extends Aware {

	void setApplicationContext(ApplicationContext applicationContext) throws BeansException;

}

当一个类实现了ApplicationContextAware接口之后,这个类就可以方便获得ApplicationContext中的所有bean;
我们可以新建工具类,实现该接口,方便获取Spring容器中的bean。

@Component
public class ApplicationContextUtils implements ApplicationContextAware {

    private static ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        context = applicationContext;
    }

    public static ApplicationContext getApplicationContext() {
        return context;
    }

    public static Object getBean(String beanName) {
        if(context != null) {
            return context.getBean(beanName);
        }
        return null;
    }

}

EnvironmentAware接口定义如下:

public interface EnvironmentAware extends Aware {
	
    void setEnvironment(Environment environment);
}

实现了EnvironmentAware接口重写setEnvironment方法后,在项目启动时可以获得application.properties的配置文件的属性值。
我们可以写一个获取属性的工具类,这里我们使用EnvironmentAware的实现类PropertySourcesPlaceholderConfigurer,工具类继承PropertySourcesPlaceholderConfigurer;
代码如下:

@Component
public class EnvUtils extends PropertySourcesPlaceholderConfigurer {

    private static ConfigurableEnvironment ENV;

    @Override
    public void setEnvironment(Environment environment) {
        super.setEnvironment(environment);
        if (environment instanceof ConfigurableEnvironment) {
            ENV = (ConfigurableEnvironment) environment;
        } else {
            ENV = new StandardEnvironment();
        }
    }

    public static String getProperty(String key) {
        return ENV.getProperty(key);
    }

}

2、BeanPostProcessor

bean后置处理器,接口定义如下:

public interface BeanPostProcessor {

	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

}

一个BeanPostProcessor可以在任意一个Bean的初始化之前以及初始化之后去额外的做一些用户自定义的逻辑,
当然,我们可以通过判断beanName来进行针对性处理(针对某个Bean,或某部分 Bean),
可以通过定义BeanPostProcessor来干涉Spring创建Bean的过程。

@Component
public class RiverBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if(Objects.equals(beanName, "userService")) {
            System.out.println("userService初始化前");
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if(Objects.equals(beanName, "userService")) {
            System.out.println("userService初始化后");
        }
        return bean;
    }
}

Spring中的AOP就是基于初始化后实现的,初始化后返回的对象才是最终的Bean对象。

3、InitializingBean、DisposableBean

InitializingBean接口定义如下:

public interface InitializingBean {

	void afterPropertiesSet() throws Exception;

}

DisposableBean接口定义如下:

public interface DisposableBean {

	void destroy() throws Exception;
}

如果Bean对象实现了InitializingBean接口,就调用其afterPropertiesSet()方法,初始化bean中的参数,或者校验参数;
InitializingBean执行在BeanPostProcessor的两个方法之间,顺序为:postProcessBeforeInitialization -> initializingBean -> postProcessAfterInitialization

如果Bean对象实现了DisposableBean接口,当容器关闭时回调destroy方式执行销毁逻辑。

@Component
public class UserBean implements InitializingBean, DisposableBean {

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("执行初始化逻辑");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("执行销毁逻辑");
    }
}

4、@PostConstruct、@PreDestroy

@PostConstruct在bean创建完成并且属性赋值完成,来执行初始化方法
@PreDestroy在关闭容器时调用;

@Service
public class AService {

    @PostConstruct
    public void init() {
        System.out.println("执行初始化逻辑");
    }

    @PreDestroy
    public void d() {
        System.out.println("容器关闭时逻辑");
    }
}

5、BeanFactoryPostProcessor

bean工厂后置处理器,该接口定义如下:

public interface BeanFactoryPostProcessor {

	void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

}

BeanFactoryPostProcessor表示Bean工厂的后置处理器,其实和BeanPostProcessor类似,
BeanPostProcessor是干涉Bean的创建过程,BeanFactoryPostProcessor是干涉BeanFactory的创建过程。
如下代码,自定义RiverBeanFactoryPostProcessor,修改bean定义由单例改为原型。

@Component
public class RiverBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("RiverBeanFactoryPostProcessor...");
		BeanDefinition beanDefinition = beanFactory.getBeanDefinition("orderService");
		beanDefinition.setScope("prototype");
	}

}

测试代码:

@Component
public class OrderService {
}
@ComponentScan("cn.river.spring")
public class AppConfig {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        System.out.println(context.getBean("orderService"));
        System.out.println(context.getBean("orderService"));
        System.out.println(context.getBean("orderService"));
    }
}

6、BeanDefinitionRegistryPostProcessor

该接口定义如下:

public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {

	void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;

}

该接口继承自BeanFactoryPostProcessor,具有BeanFactoryPostProcessor的功能,还兼具BeanDefinition注册的功能。
通过实现BeanDefinitionRegistryPostProcessor,可以将一个类注册为BeanDefinition,
这样不需要在类上加@Component注解,就可以从spring容器中获取该bean对象。

@Component
public class RiverBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        System.out.println("postProcessBeanDefinitionRegistry...");
        // 生成OrderService的bean定义            
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
        AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
        beanDefinition.setBeanClass(OrderService.class);
        registry.registerBeanDefinition("orderService", beanDefinition);
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

    }
}

7、ImportBeanDefinitionRegistrar

该接口定义如下:

public interface ImportBeanDefinitionRegistrar {

	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);

}

ImportBeanDefinitionRegistrar接口是也是spring的扩展点之一,它支持自定义BeanDefinition对象;
ImportBeanDefinitionRegistrar类只能通过其他类@Import的方式来加载,通常是启动类或配置类。
实现此接口的类会回调registerBeanDefinitions方法,将类注册到spring容器中。

public class RiverServiceRegistrar implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
        //指定bean定义信息
        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(UserService.class);
        //注册一个bean指定bean名字
        beanDefinitionRegistry.registerBeanDefinition("userService", rootBeanDefinition);
    }
}
public class UserService {
}
@Import({RiverServiceRegistrar.class})
public class ImportBeanDefinitionTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext =
                new AnnotationConfigApplicationContext(ImportBeanDefinitionTest.class);
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String name : beanDefinitionNames) {
            System.out.println(name);
        }
    }
}

Spring整合Mybatis时也会用到此扩展点。

8、SmartLifecycle

Lifecycle接口定义如下:

public interface Lifecycle {

	void start();
	void stop();
	boolean isRunning();
}

Lifecycle常用来管理一个组件的启动和停止;
Lifecycle表示的是ApplicationContext的生命周期,可以定义一个SmartLifecycle来监听ApplicationContext的启动和关闭。

@Component
public class RiverLifecycle implements SmartLifecycle {
    /**
     * 组件的运行状态
     */
    private volatile boolean running = false;

    @Override
    public void start() {
        System.out.println("lifecycle start");
        running = true;
    }

    @Override
    public void stop() {
        System.out.println("lifecycle stop");
        running = false;
    }

    @Override
    public boolean isRunning() {
        System.out.println("lifecycle running state:" + running);
        return running;
    }
}

测试:

@ComponentScan("cn.river.spring")
public class LifecycleTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(LifecycleTest.class);
        context.close();
    }
}

9、FactoryBean

FactoryBean是Spring容器实例化bean逻辑的扩展点。

接口定义如下:

public interface FactoryBean<T> {

	T getObject() throws Exception;

	Class<?> getObjectType();

	default boolean isSingleton() {
		return true;
	}

}

一般情况下,Spring通过反射机制利用bean的class属性指定实现类来实例化bean 。
在某些情况下,实例化bean过程比较复杂,Spring为此提供了FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化bean的逻辑。
后面又提供了@Configration和@Bean这种方式,一定程度上可以替代FactoryBean。

@Component
public class RiverFactoryBean implements FactoryBean {

    @Override
    public Object getObject() throws Exception {
        return new UserBean();
    }

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

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

测试:

@ComponentScan("cn.river.spring")
public class FactoryBeanTest {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(FactoryBeanTest.class);
        UserBean bean = (UserBean) context.getBean("riverFactoryBean");
        System.out.println(bean);
        Object fb = context.getBean("&riverFactoryBean");
        System.out.println(fb);
    }

}

10、ApplicationListener

ApplicationContext事件机制是观察者设计模式的实现,通过ApplicationEvent类和ApplicationListener接口,可以实现ApplicationContext事件处理。
ApplicationListener接口定义如下:

public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {

	void onApplicationEvent(E event);
}

如果容器中有一个ApplicationListener的Bean,每当ApplicationContext发布ApplicationEvent时,ApplicationListener的Bean将自动被触发。
Spring中有一些内置的事件,当完成摸个动作时会触发某些事件,如ContextRefreshedEvent事件,当所有的bean都初始化完成并被成功装载后会触发该事件,实现ApplicationListener接口可以收到监听动作。
我们也可以自定义事件监听,来完成某些业务逻辑。

@Component
public class MsgApplicationListener implements ApplicationListener<MsgEvent> {

    @Override
    public void onApplicationEvent(MsgEvent event) {
        System.out.println(event.getSource());
    }

    @EventListener
    public void handle(MsgEvent event) {
        System.out.println("注解监听: " + event);
    }
}

自定义事件,继承ApplicationEvent

public class MsgEvent extends ApplicationEvent {

    public MsgEvent(Object source) {
        super(source);
    }
}

测试代码:

@ComponentScan("cn.river.spring")
public class ApplicationListenerDemo {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ApplicationListenerDemo.class);
        MsgEvent msgEvent = new MsgEvent("发送短信");
        context.publishEvent(msgEvent);
    }
}
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值