2:Spring IOC 容器底层注解使用

二:Spring IOC 容器底层注解使用

2.1)xml配置文件的形式 VS 配置类的形式

①:基于xml的形式定义Bean的信息

<?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-->
    <bean id="person" class="com.tuling.xmlbeanfacotry.Person"></bean>
</beans>

去容器中读取Bean

public class MainClass {

    public static void main(String[] args) {
        //XmlBeanFactory xmlBeanFactory = new XmlBeanFactory(new ClassPathResource("XmlBean.xml"));
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("XmlBean.xml");
        Person person = (Person) ctx.getBean("person");
        person.run();
    }
}

 

②:基于读取配置类的形式定义Bean信息

@Configuration
public class MainConfig {

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

注意: 通过@Bean的形式是使用的话, bean的默认名称是方法名,若@Bean(value="bean的名称")

那么bean的名称是指定的

去容器中读取Bean的信息(传入配置类)

    public static void main( String[] args )
    {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MainConfig.class);
        System.out.println(ctx.getBean("person"));

    }

 

2.2)在配置类上写@CompentScan注解来进行包扫描

@Configuration

@ComponentScan(basePackages = {"com.tuling.testcompentscan"})

public class MainConfig {

}

 

①:排除用法 excludeFilters(排除@Controller注解的,和TulingService的)

 

@Configuration

@ComponentScan(basePackages = {"com.tuling.testcompentscan"},excludeFilters = {

@ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Controller.class}),

@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,value = {TulingService.class})

})

public class MainConfig {

}

 

②:包含用法 includeFilters ,注意,若使用包含的用法,需要把useDefaultFilters属性设置为false(true表

示扫描全部的)

 

@Configuration

@ComponentScan(basePackages = {"com.tuling.testcompentscan"},includeFilters = {

@ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Controller.class, Service.class})

},useDefaultFilters = false)

public class MainConfig {

}

③ @ComponentScan.Filter type的类型

a)注解形式的FilterType.ANNOTATION @Controller @Service @Repository @Compent

b)指定类型的 FilterType.ASSIGNABLE_TYPE @ComponentScan.Filter(type =

FilterType.ASSIGNABLE_TYPE,value = {TulingService.class})

c)aspectj类型的 FilterType.ASPECTJ(不常用)

d)正则表达式的 FilterType.REGEX(不常用)

e)自定义的 FilterType.CUSTOM

 

public enum FilterType {

//注解形式 比如@Controller @Service @Repository @Compent

ANNOTATION,

//指定的类型

ASSIGNABLE_TYPE,

//aspectJ形式的

ASPECTJ,

//正则表达式的

REGEX,

//自定义的

CUSTOM

}

③.①FilterType.CUSTOM 自定义类型如何使用

 

public class TulingFilterType implements TypeFilter {

@Override

public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {

//获取当前类的注解源信息

AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();

//获取当前类的class的源信息

ClassMetadata classMetadata = metadataReader.getClassMetadata();

//获取当前类的资源信息

Resource resource = metadataReader.getResource();

if(classMetadata.getClassName().contains("dao")) {

return true;

}

return false;

}

}

@ComponentScan(basePackages = {"com.tuling.testcompentscan"},includeFilters = {

@ComponentScan.Filter(type = FilterType.CUSTOM,value = TulingFilterType.class)

},useDefaultFilters = false)

public class MainConfig {

}

 

2.3)配置Bean的作用域对象

①:在不指定@Scope的情况下,所有的bean都是单实例的bean,而且是饿汉加载(容器启动实例就创建

好了)

 

@Bean

public Person person() {

return new Person();

}

②:指定@Scope为 prototype 表示为多实例的,而且还是懒汉模式加载(IOC容器启动的时候,并不会创建对象,而是在第一次使用的时候才会创建)

@Bean

@Scope(value = "prototype")

public Person person() {

return new Person();

}

③:@Scope指定的作用域方法取值

a) singleton 单实例的(默认)

b) prototype 多实例的

c) request 同一次请求

d) session 同一个会话级别

 

2.4)Bean的懒加载@Lazy(主要针对单实例的bean 容器启动的时候,不创建对象,在第一次使用的时候才会创建该对象)

@Bean

@Lazy

public Person person() {

return new Person();

}

 

2.5)@Conditional进行条件判断等.

场景,有二个组件TulingAspect 和TulingLog ,我的TulingLog组件是依赖于TulingAspect的组件

应用:自己创建一个TulingCondition的类 实现Condition接口

public class TulingCondition implements Condition {

/**

*

* @param context

* @param metadata

* @return

*/

@Override

public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {

//判断容器中是否有tulingAspect的组件

if(context.getBeanFactory().containsBean("tulingAspect")) {

return true;

}

return false;

}

}

public class MainConfig {

@Bean

public TulingAspect tulingAspect() {

return new TulingAspect();

}

//当切 容器中有tulingAspect的组件,那么tulingLog才会被实例化.

@Bean

@Conditional(value = TulingCondition.class)

public TulingLog tulingLog() {

return new TulingLog();

}

}

 

2.6)往IOC 容器中添加组件的方式

①:通过@CompentScan +@Controller @Service @Respository @compent

适用场景: 针对我们自己写的组件可以通过该方式来进行加载到容器中。

②:通过@Bean的方式来导入组件(适用于导入第三方组件的类)

③:通过@Import来导入组件 (导入组件的id为全类名路径)

@Configuration

@Import(value = {Person.class, Car.class})

public class MainConfig {

}

 

通过@Import 的ImportSeletor类实现组件的导入 (导入组件的id为全类名路径)

 

public class TulingImportSelector implements ImportSelector {

/可以获取导入类的注解信息

@Override

public String[] selectImports(AnnotationMetadata importingClassMetadata) {

return new String[]{"com.tuling.testimport.compent.Dog"};

}

}

@Configuration

@Import(value = {Person.class, Car.class, TulingImportSelector.class})

public class MainConfig {

}

通过@Import的 ImportBeanDefinitionRegister导入组件 (可以指定bean的名称)

public class TulingBeanDefinitionRegister implements ImportBeanDefinitionRegistrar {

@Override

public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

//创建一个bean定义对象

RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Cat.class);

//把bean定义对象导入到容器中

registry.registerBeanDefinition("cat",rootBeanDefinition);

}

}

@Configuration

//@Import(value = {Person.class, Car.class})

//@Import(value = {Person.class, Car.class, TulingImportSelector.class})

@Import(value = {Person.class, Car.class, TulingImportSelector.class, TulingBeanDefinitionRegister.class})

public class MainConfig {

}

 

④:通过实现FacotryBean接口来实现注册 组件

public class CarFactoryBean implements FactoryBean<Car> {

/返回bean的对象

@Override

public Car getObject() throws Exception {

return new Car();

}

/返回bean的类型

@Override

public Class<?> getObjectType() {

return Car.class;

}

/是否为单利

@Override

public boolean isSingleton() {

return true;

}

}

 

2.7)Bean的初始化方法和销毁方法.

 

①:什么是bean的生命周期?

bean的创建----->初始化----->销毁方法

由容器管理Bean的生命周期,我们可以通过自己指定bean的初始化方法和bean的销毁方法

@Configuration

public class MainConfig {

//指定了bean的生命周期的初始化方法和销毁方法.

@Bean(initMethod = "init",destroyMethod = "destroy")

public Car car() {

return new Car();

}

}

针对单实例bean的话,容器启动的时候,bean的对象就创建了,而且容器销毁的时候,也会调用Bean的销毁方法

针对多实例bean的话,容器启动的时候,bean是不会被创建的而是在获取bean的时候被创建,而且bean的销毁不受

IOC容器的管理.

 

②:通过 InitializingBean和DisposableBean 的二个接口实现bean的初始化以及销毁方法

@Component

public class Person implements InitializingBean,DisposableBean {

public Person() {

System.out.println("Person的构造方法");

}

@Override

public void destroy() throws Exception {

System.out.println("DisposableBean的destroy()方法 ");

}

@Override

public void afterPropertiesSet() throws Exception {

System.out.println("InitializingBean的 afterPropertiesSet方法");

}

}

 

③:通过JSR250规范 提供的注解@PostConstruct 和@ProDestory标注的方法

@Component

public class Book {

public Book() {

System.out.println("book 的构造方法");

}

@PostConstruct

public void init() {

System.out.println("book 的PostConstruct标志的方法");

}

@PreDestroy

public void destory() {

System.out.println("book 的PreDestory标注的方法");

}

}

④:通过Spring的BeanPostProcessor的 bean的后置处理器会拦截所有bean创建过程

postProcessBeforeInitialization 在init方法之前调用

postProcessAfterInitialization 在init方法之后调用

@Component

public class TulingBeanPostProcessor implements BeanPostProcessor {

@Override

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {

System.out.println("TulingBeanPostProcessor...postProcessBeforeInitialization:"+beanName);

return bean;

}

@Override

public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {

System.out.println("TulingBeanPostProcessor...postProcessAfterInitialization:"+beanName);

return bean;

}

}

BeanPostProcessor的执行时机

populateBean(beanName, mbd, instanceWrapper)

initializeBean{

applyBeanPostProcessorsBeforeInitialization()

invokeInitMethods{

isInitializingBean.afterPropertiesSet

自定义的init方法

}

applyBeanPostProcessorsAfterInitialization()方法

}

2.8)通过@Value + @PropertySource来给组件赋值

public class Person {

//通过普通的方式

@Value("司马")

private String firstName;

//spel方式来赋值

@Value("#{28-8}")

private Integer age;

通过读取外部配置文件的值

@Value("${person.lastName}")

private String lastName;

}

@Configuration

@PropertySource(value = {"classpath:person.properties"}) //指定外部文件的位置

public class MainConfig {

@Bean

public Person person() {

return new Person();

}

}

 

2.9)自动装配

@AutoWired的使用

自动注入:

//一个Dao

@Repository

public class TulingDao {

}

@Service

public class TulingService {

@Autowired

private TulingDao tulingDao;

结论:

a:自动装配首先时按照类型进行装配,若在IOC容器中发现了多个相同类型的组件,那么就按照 属性名称来进行装配

@Autowired

private TulingDao tulingDao;

比如,我容器中有二个TulingDao类型的组件 一个叫tulingDao 一个叫tulingDao2

那么我们通过@AutoWired 来修饰的属性名称时tulingDao,那么拿就加载容器的tulingDao组件,若属性名称为

tulignDao2 那么他就加载的时tulingDao2组件

b:假设我们需要指定特定的组件来进行装配,我们可以通过使用@Qualifier("tulingDao")来指定装配的组件

或者在配置类上的@Bean加上@Primary注解

@Autowired

@Qualifier("tulingDao")

private TulingDao tulingDao2;

c:假设我们容器中即没有tulingDao 和tulingDao2,那么在装配的时候就会抛出异常

No qualifying bean of type 'com.tuling.testautowired.TulingDao' available

若我们想不抛异常 ,我们需要指定 required为false的时候可以了

@Autowired(required = false)

@Qualifier("tulingDao")

private TulingDao tulingDao2;

d:@Resource(JSR250规范)

功能和@AutoWired的功能差不多一样,但是不支持@Primary 和@Qualifier的支持

e:@InJect(JSR330规范)

需要导入jar包依赖

功能和支持@Primary功能 ,但是没有Require=false的功能

<dependency>

<groupId>javax.inject</groupId>

<artifactId>javax.inject</artifactId>

<version>1</version>

</dependency>

f:使用autowired 可以标注在方法上

标注在set方法上

//@Autowired

public void setTulingLog(TulingLog tulingLog) {

this.tulingLog = tulingLog;

}

标注在构造方法上

@Autowired

public TulingAspect(TulingLog tulingLog) {

this.tulingLog = tulingLog;

}

标注在配置类上的入参中(可以不写)

@Bean

public TulingAspect tulingAspect(@Autowired TulingLog tulingLog) {

TulingAspect tulingAspect = new TulingAspect(tulingLog);

return tulingAspect;

}

3.0) 我们自己的组件 需要使用spring ioc的底层组件的时候,比如 ApplicationContext等

我们可以通过实现XXXAware接口来实现

@Component

public class TulingCompent implements ApplicationContextAware,BeanNameAware {

private ApplicationContext applicationContext;

@Override

public void setBeanName(String name) {

System.out.println("current bean name is :【"+name+"】");

}

@Override

public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

this.applicationContext = applicationContext;

}

}

3.1)通过@Profile注解 来根据环境来激活标识不同的Bean

@Profile标识在类上,那么只有当前环境匹配,整个配置类才会生效

@Profile标识在Bean上 ,那么只有当前环境的Bean才会被激活

没有标志为@Profile的bean 不管在什么环境都可以被激活

@Configuration

@PropertySource(value = {"classpath:ds.properties"})

public class MainConfig implements EmbeddedValueResolverAware {

@Value("${ds.username}")

private String userName;

@Value("${ds.password}")

private String password;

private String jdbcUrl;

private String classDriver;

@Override

public void setEmbeddedValueResolver(StringValueResolver resolver) {

this.jdbcUrl = resolver.resolveStringValue("${ds.jdbcUrl}");

this.classDriver = resolver.resolveStringValue("${ds.classDriver}");

}

//标识为测试环境才会被装配

@Bean

@Profile(value = "test")

public DataSource testDs() {

return buliderDataSource(new DruidDataSource());

}

//标识开发环境才会被激活

@Bean

@Profile(value = "dev")

public DataSource devDs() {

return buliderDataSource(new DruidDataSource());

}

//标识生产环境才会被激活

@Bean

@Profile(value = "prod")

public DataSource prodDs() {

return buliderDataSource(new DruidDataSource());

}

private DataSource buliderDataSource(DruidDataSource dataSource) {

dataSource.setUsername(userName);

dataSource.setPassword(password);

dataSource.setDriverClassName(classDriver);

dataSource.setUrl(jdbcUrl);

return dataSource;

}

}

激活切换环境的方法

方法一:通过运行时jvm参数来切换 -Dspring.profiles.active=test|dev|prod

方法二:通过代码的方式来激活

public static void main(String[] args) {

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();

ctx.getEnvironment().setActiveProfiles("test","dev");

ctx.register(MainConfig.class);

ctx.refresh();

printBeanName(ctx);

}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我! 毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JackXiang2019

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值