导包
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.13.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
传统的xml格式与注解开发的对比
首先准备一个Person类:
public class Person {
private String name;
private Integer age;
//getter、setter、无参构造、有参构造、toString省略
}
xml格式
-
第一步,首先需要准备一份xml配置文件
<?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.atguigu.pojo.Person"> <property name="name" value="zhangsan"></property> <property name="age" value="22"></property> </bean>
-
第二步,通过资源加载器去加载文件
ApplicationContext context = new ClassPathXmlApplicationContext("my-context-beans.xml"); Person person = (Person)context.getBean("person"); System.out.println(person);
注解开发模式
-
1、首先需要准备一份配置类:
@Configration public class MyConfigration { /** * @Bean 相当于bean标签, * 返回值类型是最后的返回类型, * 方法名是默认id * @Bean 将某个容器注入到IOC容器中 * @return */ @Bean("person") public Person person01 (){ return new Person("lisi" , 24); } }
-
2、通过注解加载器去加载:
//创建一个通过注解方式注入bean的对象 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfigration.class); /*Person person = context.getBean(Person.class); System.out.println("person = " + person);*/ String[] definitionNames = context.getBeanDefinitionNames(); for(String name : definitionNames){ System.out.println(name); }
@ComponentScan
/**
* @Configuration 相当于之前的xml文件,只是这里转换成了java配置
* @ComponentScan 配置包扫描,basePackages属性是配置要扫描的类
* excludeFilters配置的是排除要扫描的类的信息
* includeFilters配置的是需要扫描指定过滤类的信息,使用时需要关闭默认的过滤类型,useDefaultFilters = false
* 常用的过滤信息有四个,他们分别是
* FilterType.ANNOTATION:通过注解进行过滤,
* FilterType.ASSIGNABLE_TYPE,通过类型进行过滤
* FilterType.ASPECTJ:通过AspectJ的方式进行过滤
* FilterType.REGEX:通过正则表达式的方式进行过滤
* FilterType.CUSTOM:自定义过滤规则
* @ComponentScans 可以配置多个扫描器,每一个扫描器都是一个单独的@ComponentScan
*
*/
@Configuration
/*@ComponentScan(basePackages = "com.atguigu" ,includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION , classes = {Controller.class , Service.class } )
})*/
@ComponentScan(basePackages = "com.atguigu",includeFilters = {
@ComponentScan.Filter(type = FilterType.CUSTOM , classes = MyTypeFilter.class)
},useDefaultFilters = false)
public class MyConfigration {
/**
* @Bean 相当于bean标签,
* 返回值类型是最后的返回类型,
* 方法名是默认id
* @Bean 将某个容器注入到IOC容器中
* @return
*/
@Bean("person")
public Person person01 (){
return new Person("lisi" , 24);
}
}
/**
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class,Service.class}),通过注解的方式进行过滤
@ComponentScan.Filter(type = FilterType.CUSTOM , classes = MyTypeFilter.class),这是一个自定义过滤规则
*/
自定义过滤规则
public class MyTypeFilter implements TypeFilter {
/**
*
* @param metadataReader 读取的是扫描的包中的注解,类,的信息
* @param metadataReaderFactory 读取的是其他任何包中的注解,类,的信息
* @return true代表是将对应的信息放置IOC容器,false是不放置在容器
* @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);
//若名称中包含的per,就加入到spring容器
if(className.contains("per")){
return true;
}
return false;
}
}
@Scope作用域和@Lazy懒加载
@Scope作用域
singleton:当容器启动的时候,会将对象放入IOC容器,第二次直接去容器当中取,相当于map.get(),容器创建时会创建对象并加入IOC容器
prototype:每次都会得到一个全新的对象,不会放入IOC容器,容器创建时,不会创建对象,当获取对象时,才会创建对象
request:在同一个请求当中,对象是唯一的
session:在同一个会话中,对象是唯一的
懒加载
前提:必须保证Bean的Scope是单例的,容器启动时bean就会创建;
懒加载,就是容器启动时先不创建bean,当第一次调用对象的时候,将对象定义并初始化,并加入到IOC容器中;
@Conditional条件匹配
1、在@Configuration中注入一个@Bean
@Bean("Bill")
@Conditional({LinuxCondition.class})
public Person person01(){
return new Person("Bill Gates" , 62);
}
2、创建的条件匹配LinuxCondition对象的内容为:
public class LinuxCondition implements Condition {
/**
*
* @param context ConditionContext 上下文对象
* @param metadata AnnotatedTypeMetadata 当前带有注解的类
* @return
*/
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//获取环境信息对象
Environment environment = context.getEnvironment();
//获取系统信息
String property = environment.getProperty("os.name");
if(property.contains("linux")){
return true;
}
return false;
}
}
3、方法上加入的@Conditional({LinuxCondition.class}),只有满足条件才会加入到IOC容器中,也可以作用到类上,此类所有的Bean只有满足才会加入IOC;
Import导入的四种方式
-
Configuration对象的前缀
@Configuration @Conditional({WindowsCondition.class}) @Import({Color.class , MyImportSelector.class , MyImportBeanDefinitionRegistrar.class}) public class MyConfigration2
1、import导入
-
Color实体类:
public class Color{}
-
创建好实体类之后,可直接通过@Import导入即可,生成对象的id名为完整的包路径+类名
2、ImportSelector方式:
-
Blue实体类:
public class Blue{}
-
Yellow实体类:
public class Yellow{}
-
自定义一个ImportSelector实现类,这里有一个例子:
public class MyImportSelector implements ImportSelector { /** * * @param importingClassMetadata AnnotationMetadata 带有注解类信息 * @return */ public String[] selectImports(AnnotationMetadata importingClassMetadata) { //这里返回的可以是空数组,但不能是null return new String[]{"com.atguigu.pojo.Blue" , "com.atguigu.pojo.Yellow"}; } }
-
创建好实体类之后,自定义一个ImportSelector实现类,并重写对应的方法,@Import导入即可,生成对象的id名为完整的包路径+类名
3、ImportBeanDefinitionRegistrar方式:
-
Red实体类:
public class Red{}
-
自定义一个ImportBeanDefinitionRegistrar 实现类,这里有一个例子:
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { /** * * @param importingClassMetadata AnnotationMetadata带有注解的类的信息 * @param registry BeanDefinitionRegistry:Bean对象注册器 */ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { //获取所有的Bean名称 String[] beanDefinitionNames = registry.getBeanDefinitionNames(); List<String> strings = Arrays.asList(beanDefinitionNames); if(strings.contains("com.atguigu.pojo.Color") && strings.contains("com.atguigu.pojo.Blue")) { //创建一个RootBeanDefinition对象 RootBeanDefinition beanDefinition = new RootBeanDefinition(Red.class); registry.registerBeanDefinition("red", beanDefinition); } }
-
ImportBeanDefinitionRegistrar方式创建的bean,Bean的id是自己命名的
4、FactoryBean方式导入
/**
* FactoryBean 是一个工厂bean的接口,需要一个实现类去实现FactoryBean接口
* getObject 需要返回的对象
* getObjectType 返回的对象类型
* isSingleton 是否为单例,true为单例,false为多例
*/
@Component
public class ColorFactoryBean implements FactoryBean<Color> {
public Color getObject() throws Exception {
System.out.println("创建了Bean实例对象");
return new Color();
}
public Class<?> getObjectType() {
return Color.class;
}
public boolean isSingleton() {
return false;
}
}
-
通过ComponentScan进行包扫描;
ApplicationContext context = new AnnotationConfigApplicationContext(MyConfigration2.class); //带&返回的是colorFactoryBean对象,可以去BeanFactory类中取查对应的前缀"&" Object colorFactoryBean = context.getBean("&colorFactoryBean"); System.out.println(colorFactoryBean.getClass()); //不带&返回的是Color对象 Object colorFactoryBean1 = context.getBean("colorFactoryBean");