spring(一):基本组件的使用

1.spring(一):基本组件的使用

1.1. 体系架构

1、 Spring Core:即,Spring核心,它是框架最基础的部分,提供IOC和依赖注入特性

2、 Spring Context:即,Spring上下文容器,它是BeanFactory功能加强的一个子接口

3、 Spring Web:它提供Web应用开发的支持

4、 Spring MVC:它针对Web应用中MVC思想的实现

5、 Spring DAO:提供对JDBC抽象层,简化了JDBC编码,同时,编码更具有健壮性。

6、 Spring ORM:它支持用于流行的ORM框架的整合,比如:Spring + Hibernate、Spring + iBatis、Spring + JDO的整合等等。

7、 Spring AOP:AOP即,面向切面编程,它提供了与AOP联盟兼容的编程实现。

注:文章中使用的spring版本为5.0.6.RELEASE。

1.2.spring使用基础

bean注入

  • 基于xml的bean注入 调用
	<bean id="person" class="com.enjoy.cap1.Person">
		<property name="name" value="james"></property>
		<property name="age" value="19"></property>
	</bean>
	
	ApplicationContext ac =  new ClassPathXmlApplicationContext("beans.xml");
		Person person = (Person)ac.getBean("person");
		System.out.println(person);
  • 基于配置的bean注入、调用
@Configuration
public class Mainconfig {
	
	@Bean("abcPerson")
	public Person person() {
		return new Person("ma",20);
	}
}

测试类:
ApplicationContext ac = new AnnotationConfigApplicationContext(Mainconfig.class);
Person person = (Person)ac.getBean("abcPerson");
System.out.println(person);
String[] namesForBean = ac.getBeanNamesForType(Person.class);
for(String name : namesForBean) {
	System.out.println(name);//读的配置文件中的方法名;存在map里  key 是方法名或者自己定义的,值是返回值的对象
}
  • bean最后都放进map里面

扫描包

  • 扫描包 ComponentScan
@Configuration
@ComponentScan(value = "com.enjoy.cap2",excludeFilters= {
		@Filter(type=FilterType.ANNOTATION,classes={Controller.class})
		
},useDefaultFilters=true)
//定义哪些包不扫描
public class Cap2MainConfig {

	@Bean()
	public Person person() {
		return new Person("ma",20);
	}
}
  • FilterType参数:

    • 注解 ANNOTATION
    • 指定哪个类 ASSIGNABLE_TYPE
    • ASPECTJ
    • REGEX
    • 自定义java类 CUSTOM:设置为自定义类型,指向自己定义的class文件
    public class MyTypeFilter implements TypeFilter {
    
    	/*
    	 * metadataReader:读取到当前正在扫描类的信息
    	 * metadataReaderFactory:可以获取其他任何类信息
    	 */
    	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;
    	}
    
    }
    
    使用:@ComponentScan(value = "com.enjoy.cap2",includeFilters= {
    		@Filter(type=FilterType.CUSTOM,classes={MyTypeFilter.class})
    		
    },useDefaultFilters=false)
    设置为自定义类型,指向自己定义的class文件
    
  • useDefaultFilters = true时会默认加载所有@Component的组件,@controller @service 实现上都用到了这个组件,所以一直会被加载,无法过滤。

作用域

  • Singleton:单实例, IOC启动时创建 ,每次从IOC容器中获取(大Map.get)
  • prototype:多实例, IOC启动时不创建对象 ,每次调用的时候创建
  • 对应 单例模式和原型模式2种设计模式。
@Configuration
public class Cap3MainConfig {
	/*
	 * prototype:多实例, IOC启动时不创建对象 ,每次调用的时候创建
	 * Singleton:单实例, IOC启动时创建 ,每次从IOC容器中获取(大Map.get)
	 * request:web应用  递交一次创建一个实例
	 * session:同一个session创建一个实例
	 */
	@Scope("prototype")
	@Bean
	public Person person() {
		return new Person("ma",20);
	}
}

	@Test
	public void test01() {
		AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Cap3MainConfig.class);
		String[] names = ac.getBeanDefinitionNames();
		for(String name : names) {
			System.out.println(name);
		}
		
		Object bean1 = ac.getBean("person");
		System.out.println(bean1);
		Object bean2 = ac.getBean("person");
		System.out.println(bean2);
		if(bean1 == bean2) {
			System.out.println("bean1 == bean2");
		}
	}

懒加载

  • IOC初始化的时候不创建对象,调用的时候才创建对象。
  • 只创建一次
  • 对象的引用在IOC容器里面有 但是没有创建
@Configuration
public class Cap4MainConfig {
	@Lazy
	@Bean
	public Person person() {
		System.out.println("创建对象");
		return new Person("ma",20);
	}
}


	@Test
	public void test01() {
		AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Cap4MainConfig.class);
		System.out.println("ioc容器创建完成");
		String[] names = ac.getBeanDefinitionNames();//这里面有person 但是并没有创建
		for(String name : names) {
			System.out.println(name);
		}
		
		Object bean1 = ac.getBean("person");//执行获取的时候才创建bean
		System.out.println(bean1);
		
	}

条件注册bean

  • IOC就是对我们bean进行管理:注册、实例化、管理
  • 有选择的条件注册:实现spring的condition接口 -> @condition指向条件 ->创建测试
  • FactoryBean:把javabean实例通过beanFactory放到IOC容器中
  • beanFactory:从容器中获取实例化后的bean
public class WinCondition implements Condition {// org.springframework.context.annotation.Condition;
	/*
	 * ConditionContext:判断可以使用的上下文(环境)
	 * AnnotatedTypeMetadata:注解的信息
	 */
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		//能获取到IOC容器正在使用的beanFactory
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		//当前环境变量
		Environment environment = context.getEnvironment();
		String os_name = environment.getProperty("os.name");
		//System.out.println(os_name);
		if(os_name.contains("Windows")) {
			return true;
		}
		return false;
	}
}

@Configuration
public class Capter5MainConfig {

	@Bean("person")
	public Person person() {
		System.out.println("容器中添加。。person");
		return new Person("ma",20);
	}
	
	@Bean("tom")
	@Conditional(WinCondition.class)
	public Person tom() {
		System.out.println("容器中添加。。tom");
		return new Person("tom",20);
	}
	
public class Test05 {
	@Test
	public  void test05() {
		AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(Capter5MainConfig.class);
		System.out.println("ioc 容器初始化完成");
	}
}
- 设置启动参数:-Dos.name=linux 可以测试linux下实例化哪个bean

@Import注册bean

在容器中注册组件的方式

  • @Bean:导入第三方的组件或者类
  • 包扫描+组件标注注解 @ComponentScan:@controller @service @ Reponsitory @ Componet
@Configuration
@Import(value= {Dog.class,IimportSelector.class,MyImportReg.class})
public class Capter6MainConfig {
	@Bean("person")
	public Person person() {
		System.out.println("容器中添加。。person");
		return new Person("ma",20);
	}
	

	@Bean
	public MyFactoryBean myFactory() {
		return new MyFactoryBean();
	}
}
  • @Import :快速给容器导入一个组件,@Bean比较简单

    • @Import(要导入到容器中的组件):容器会自动注册这个组件,bean的ID为全类名
    • ImportSelector:接口,返回需要导入到容器的组件的全类名数组
    public class IimportSelector implements ImportSelector {
    
    	public String[] selectImports(AnnotationMetadata importingClassMetadata) {
    		// TODO Auto-generated method stub
    		return new String[]{"com.enjoy.cap6.bean.Fish1","com.enjoy.cap6.bean.Fish2"};
    	}
    }
    
    • ImportBeanDefinitionRegistrar:可以手动添加bean实例到IOC容器,所有bean的注册可以使用BeanDefinitionRegistry;
      实现ImportBeanDefinitionRegistrar接口
    public class MyImportReg implements ImportBeanDefinitionRegistrar {
    	/*
    	 * AnnotationMetadata:当前类的注解信息
    	 * BeanDefinitionRegistry:BeanDefinition注册类
    	 * 		把所有需要加到容器的bean加入
    	 */
    	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    		boolean bean1 = registry.containsBeanDefinition("com.enjoy.cap6.bean.Dog");
    		if(bean1) {//如果IOC容器中存在这个类,加入下面的类
    			//对于要注册的类,要给bean进行封装
    			RootBeanDefinition bean = new RootBeanDefinition(Pig1.class);
    			registry.registerBeanDefinition("pig", bean);//完成的操作:this.beanDefinitionMap.put(beanName, beanDefinition);
    		}
    	}
    
    }
    
  • 使用spring提供的FactoryBean(工厂Bean)进行注册

    • bean名称没有&符号开头的 最终会调factory.getObject();方法返回放进去的对象
public class MyFactoryBean implements FactoryBean<Monkey> {

	public Monkey getObject() throws Exception {
		// TODO Auto-generated method stub
		return new Monkey();
	}

	public Class<?> getObjectType() {
		// TODO Auto-generated method stub
		return Monkey.class;
	}
}

@Value

  • 使用@Value进行赋值:

    • 基本字符
    • SpringEl 表达式 @Value("#{20-8}")
    • 读取配置文件 @Value("${bird.color}")
    public class Bird {
    	@Value("zhangsan")
    	private String name;
    	@Value("#{20-8}")
    	private Integer age;
    	@Value("${bird.color}")
    	private String color;
    }
    
    @Configuration
    @PropertySource(value="classpath:/test.properties")//配置信息加载到环境中,resources目录下
    public class Cap8MainConfig {
    
    	@Bean
    	public Bird bird() {
    		return new Bird();
    	}
    }
    
    
    	@Test
    	public void test08() {
    		AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Cap8MainConfig.class);
    		String[] names = app.getBeanDefinitionNames();
    		for(String name:names) {
    			//System.out.println(name);
    		}
    		Object bean = app.getBean("bird");
    		System.out.println(bean);
    		
    		System.out.println("IOC over");
    		
    		ConfigurableEnvironment environment = app.getEnvironment();
    		System.out.println(environment.getProperty("bird.color"));
    		app.close();
    	}
    

1.3. Bean的生命周期

初始化、销毁方法

  • Bean的生命周期指Bean创建–>初始化–>销毁的过程

  • ioc容器关闭:close中的destory就是把map清空

  • 实例化对象的2种方式:CGlib java动态代理。实现了接口的用动态代理。

  • 1, 指定初始化init-method方法

    2, 指定销毁destory-method方法

public class Bike {

	public Bike() {
		System.out.println("bike constructr...");
	}
	
	public void init() {
		System.out.println("bike init ...");
	}
	
	public void destory() {
		System.out.println("bike destory");
	}
}

@Configuration
public class Cap7MainLifeCycle {	
	@Bean(initMethod = "init",destroyMethod = "destory")
	public Bike bike() {
		return new Bike();
	}
}

	@Test
	public void test01() {
		AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Cap7MainLifeCycle.class);
		System.out.println("ioc 创建完成");
		String[] names = app.getBeanDefinitionNames();
		for(String name:names) {
			System.out.println(name);
		}
		
		System.out.println("----------------");
		app.close();
		/*
		 * close中的destory就是把map清空
		 * 		this.containedBeanMap.clear(); this.dependentBeanMap.clear(); this.dependenciesForBeanMap.clear();
		 */
	}
  • 单实例bean容器自动化处理 创建-初始化-销毁
  • 多实例:getBean 才创建。–业务 数据库连接池

继承接口

  • 继承 InitializingBean,DisposableBean接口,添加初始化时和销毁前的方法

  • 1, 实现InitializingBean接口的afterPropertiesSet()方法,当beanFactory创建好对象,且把bean所有属性设置好之后,会调这个方法,相当于初始化方法

    2, 实现DisposableBean的destory()方法,当bean销毁时,会把单实例bean进行销毁

@Component
public class Train implements InitializingBean,DisposableBean{
	public Train() {
		System.out.println("train 构造方法");
		
	}	
	//销毁前执行
	public void destroy() throws Exception {
		System.out.println("train destory");
		
	}
	//设置完属性执行
	public void afterPropertiesSet() throws Exception {
		System.out.println("bean 属性设置完成,和初始化同一时间段");
	}
}

扫描:@ComponentScan("com.enjoy.cap7.bean")

JSR规范250

  • 可以使用JSR250规则定义的(java规范)两个注解来实现

    ​ @PostConstruct: 在Bean创建完成,且属于赋值完成后进行初始化,属于JDK规范的注解

    ​ @PreDestroy: 在bean将被移除之前进行通知, 在容器销毁之前进行清理工作

  • 本地环境中没有这个,还需要配置

  • 2个注解直接在方法名上写即可。

1.4.自动装配

  • 自动装配涉及的注解 :@Autowired @Qualifier @Primary

    • @Autowired自动将容器中的实例绑定到参数上;先找@Bean标注的,再找扫描的。先按ID找 再按类型找
      • 在参数、方法、注解、构造等上都可以
    • @Qualifier 实例有多个bean的时候指定用哪个 – 根据ioc中map的key值确定;Qualifier的优先级最高
    • @Primary//设置primary之后默认引用的是这个;@Qualifier还是根据名字取找
      //spring进行自动装配的时候默认首选的bean
  • 查看源码,在解析的时候先判断有没有Qualifier ,然后再看有没有Primary,有的话用它标记的实例。

    @Configuration
    @ComponentScan({"com.enjoy.cap9.*"})
    public class Cap9MainConifg {
    	//@Primary//设置primary之后默认引用的是这个;@Qualifier还是根据名字取找
    		//spring进行自动装配的时候默认首选的bean
    	@Bean("orederDao")
    	public OrederDao orederDao() {//名字相同的时候;先找这里标注的,再找扫面的用--这里是先执行的部分,优先级比扫描的高
    		//名字不同找跟类名相同的
    		OrederDao orederDao2 = new OrederDao(); 
    		orederDao2.setFlag("2");
    		return orederDao2;
    	}
    }
    
    
    @Service
    public class OrderService {
    	//@Qualifier("orederDao")//如果Qualifier标注了,就先找这个名字对应的实例;
    	//@Autowired(required = false)
    	//@Resource //找不到引用
    	@Inject
    	private OrederDao orderDao;
    	
    	public void fun2() {
    		System.out.println("order service..."+ orderDao.toString());
    	}
    	
    	public String  fun3() {
    		System.out.println("order service..."+ orderDao.toString());
    		return "order service..."+ orderDao.toString();
    	}
    }
    
    
    	@Test
    	public void test08() {
    		AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Cap9MainConifg.class);
    		
    		OrderService service = app.getBean(OrderService.class);
    		service.fun2();
    		
    		OrederDao dao = app.getBean(OrederDao.class);
    		System.out.println(dao);
    		
    		app.close();
    	}
    
  • 是什么:spring利用依赖注入(DI), 完成对IOC容器中的各个组件的依赖关系赋值

思考与操作?

​ 1,bean组件加载优先级?

  • 单例–默认加载
  • 多个:
    • 同名:加载配置文件中@Bean标注的,先执行再扫描,这边的先用–会报错
    • 不同名:加载跟类名相同名字的
  • @Qualifier制定了名称,加载指定名称的;
  • @Primary 标注了,spring默认使用这个,而不是跟类名字相同的

​ 2,如果容器中存在两个id相同的bean, 会加载哪个bean呢?

​ 3,如何指定装配组件ID进行加载?@Qualifier

​ 4,容器加载不存在的bean会出现什么问题?

​ 5,@Primary 注解bean首选如何使用?

  • spring 默认加载的实例

​ 6,@Autowired @Resource @Inject区别?

  • @Autowired

    • 支持required = fasle 查不到不会报错
    • 支持primary
  • @Resource 效果与autowire一样可以装配bean

    • resource不支持primary
    • resource autowired false
  • @Inject :–自定义的容器可以用;不用spring

    • 第三方的,jsr规范 javax.inject,需要引用
    • 支持primary
    • 没有required = fasle
  • 自动装配原理:集成Aware接口。

    • Aware为空, 自己实现。后置处理器检查时会拿继承Aware接口的实现类去处理bean,进行后置处理
    • 自定义组件想要使用Spring容器底层 的组件(ApplicationContext, BeanFactory, …)
    • 自定义组件实现xxxAware, 在创建对象的时候, 会调用接口规定的方法注入到相关组件
  • 在这里插入图片描述

ApplicationContextAware接口: 获取IOC容器

BeanNameAware接口: 获取Bean信息

EmbeddedValueResolverAware接口: 解析器(表达式及相关脚本解析)

@Component//还需要自己注入到容器中
public class TestAware  implements ApplicationContextAware,BeanNameAware{

	private ApplicationContext context;
	
	@Override
	public void setBeanName(String name) {
		System.out.println("当前bean的名字:"+name);//当前bean的名字:testAware
		
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		// TODO Auto-generated method stub
		System.out.println("传入的ioc容器:"+applicationContext);
		this.context = applicationContext;
	}
	//传入的ioc容器:org.springframework.context.annotation.AnnotationConfigApplicationContext@3c679bde: 
	//startup date [Sun Mar 15 21:24:04 CST 2020]; root of context hierarchy
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值