文章目录
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
- @Autowired自动将容器中的实例绑定到参数上;先找@Bean标注的,再找扫描的。先按ID找 再按类型找
-
查看源码,在解析的时候先判断有没有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
}