spring ---> IOC -->DI
Dog dog= new Dog();
application.xml--->
IOC 管理
<bean id="dog" class="com.cang.Dog">
Spring 是一个开源轻量级框架,为了解决企业应用复杂的业务
可以说Spring是企业应用开发“一站式” 解决方案
注解:
IOC AOP
Spring 的目标
1,让现有的技术更加容易使用,
2,促进来良好的编程习惯
它坚持的一个原则就是不重复新造轮子;
Spring体系结构
1,Soring Core spring核心,他是框架最基础的部分,提供IOC和依赖注入特性;
2,Spring Context ,Spring 上下文容器,他是BeanFactory功能加强的一个子接口
3,SpringWeb 他提供web应用开发支持
4,Spring MVC 他正对Web应用中MVC思想的实现;
5,Spring DAO 提供JDBC抽象层,简化JDBC编码,同时 ,编码更具有健壮性。
6,Spring ORM 他支持用于流行的ORM框架整合,比如 SPring +Hibemate ,Spring +iBatis,Spring+JDO等框架整合等等。
7,Spring AOP :AOP,面向机切面编程,他提供了与AOP联盟兼容的编程实现
class Test{} bean -->
AOP
@Watch("") //看电影,观察 你有没有买电影票 做一个钱箱控制 ,在进入方法之前可以做一个判断
@Transaction(“”) // 添加一个事务
public void watchMovie (){
}
把这个 bean 初始化之后 放在IOC 容器里面
@Configuration
1,@Configuration 这种更简单
class Test{}
2,与bean.xml 的的联系
效果 一样的
@COmponentScan 扫描规则
1,指定扫描范围;
2,扫描过滤器
3,自定义过滤器
package com.enjoy.cap2.config; import org.springframework.core.io.Resource; import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.ClassMetadata; import org.springframework.core.type.classreading.MetadataReader; import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.core.type.filter.TypeFilter; import java.io.IOException; /** * MetadataReader读取到当前正在扫描类的信息 * MetadataReaderFactory 可以获取到类的所有信息 */ public class jamesTyperFilter implements TypeFilter { 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")){ return true; //当我们的类包含er的时候 则匹配成功 } return false; } }
Spring 是单实例的
单实例和多实例有什么区别?
多实例 :就是你使用的时候才会创建这个bean ,一个实例死掉了 我还可以用另一个实例啊;
单实例: 创建IOC 容器的时候这个bean 就被创建了
@Lazy 懒加载
/** * 懒加载 针对的是单实例bean : 默认在容器中启动的时候创建对象 * 懒加载:容器启动的时候不创建对象,仅当第一次使用 bean的时候才创建 初始化 * @return */
第二课
IOC 就是对我们bean 进行管理: bean 注册实例化 管理
运行测试用例的时候,操作系统是Windows,我就让Lison 这个实例对象到容器
linux : james 这个实例对象到容器中
FactoryBean BeanFactory 的区别?
FactoryBean : 可以把我们的Java实例Bean 通过FactoryBean注入到容器中;
BeanFactory : 从我们的容器中获取实例化后的bean
@Condition 条件注册bean
package com.enjoy.cap5.config; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; import org.springframework.core.env.Environment; import org.springframework.core.type.AnnotatedTypeMetadata; public class WinCondition implements Condition { /** * ConditionContext: 判断条件可以判断条件(环境) * * @param context * @param annotatedTypeMetadata * @return */ public boolean matches(ConditionContext context, AnnotatedTypeMetadata annotatedTypeMetadata) { //能够获取到IOC 容器正在使用的beanFactory ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); // 获取当前的环境变量(操作系统是win 还是linux) Environment environment = context.getEnvironment(); String property = environment.getProperty("os.name"); if(property.contains("Windows")){ return true; } return false; } } package com.enjoy.cap5.config; import com.enjoy.cap1.Person; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; @Configuration public class Cap5MainConfig { @Bean("person") public Person person() { System.out.println("给容器添加person。。。。。"); return new Person("person",20); } @Conditional(WinCondition.class) @Bean("lison") public Person lison() { System.out.println("给容器添加lison。。。。。"); return new Person("lison",58); } @Conditional(LinuxCondition.class) @Bean("james")//bean 在容器的id 为james ,IOC容器MAP public Person james() { System.out.println("给容器添加james。。。。。"); return new Person("lison",20); } }
@Import 注册bean
package com.enjoy.cap6.config; import com.enjoy.cap1.Person; import com.enjoy.cap5.config.LinuxCondition; import com.enjoy.cap5.config.WinCondition; import com.enjoy.cap6.bean.Dog; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @Configuration @Import(value ={Dog.class}) public class Cap6MainConfig { /** * 给容器中注册组件 * 1,@Bean 导入第三方的类包的组件,比如Person为第三方的类,需要在我们的IOC容器中使用 *,2, 包扫描+组件的标注注解 @ConponentSan :@Controller,@Service,@Reponsitory @Componet) 一般是针对我们自己写的类 * 3,@Import : 能够快速给容器导入一个组件 注意:@Bean 有点简单 * */ // 容器启动时初始化person的bean实例 @Bean("person") public Person person() { System.out.println("给容器添加person。。。。。"); return new Person("james",20); } } package com.enjoy.cap6.config; import org.springframework.context.annotation.ImportSelector; import org.springframework.core.type.AnnotationMetadata; public class JamesImportSelect implements ImportSelector { public String[] selectImports(AnnotationMetadata annotationMetadata) { // 返回全类名 return new String[]{"com.enjoy.cap6.bean.Fish","com.enjoy.cap6.bean.Tiger"}; } }
package com.enjoy.cap6.config; import com.enjoy.cap1.Person; import com.enjoy.cap5.config.LinuxCondition; import com.enjoy.cap5.config.WinCondition; import com.enjoy.cap6.bean.Cat; import com.enjoy.cap6.bean.Dog; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @Configuration @Import(value ={Dog.class, Cat.class,JamesImportSelect.class,JamesImportBeanDefinitionRegistrar.class}) public class Cap6MainConfig { /** * 给容器中注册组件 * 1,@Bean 导入第三方的类包的组件,比如Person为第三方的类,需要在我们的IOC容器中使用 *,2, 包扫描+组件的标注注解 @ConponentSan :@Controller,@Service,@Reponsitory @Componet) 一般是针对我们自己写的类 * 3,@Import : 能够快速给容器导入一个组件 注意:@Bean 有点简单 * a, @Import ( 要导入到容器中的组件): 容器中会自动注册到这个组件,bean 的id 为全类名 * b,ImportSelector: 是一个接口 返回需要导入到容器的组件的全类名数组 * c,ImportBeanDefinitionRegistrar: 可以手动添加到IOC 容器,所有Bean的注册可以使用BeanDifinitionRegistar, * */ // 容器启动时初始化person的bean实例 @Bean("person") public Person person() { System.out.println("给容器添加person。。。。。"); return new Person("james",20); } }
CompoentScan ....
Bean 的生命周期 bean 创建 ----》 初始化 -----》 销毁的过程
我们可以自定义bean初始化和销毁的方法
容器在bean进行到当前生命周期的时候,来调用自定义的初始化和销毁的方法
容器创建过程中: 单实例完全被创建的
package com.enjoy.cap7.config; import com.enjoy.cap1.Person; import com.enjoy.cap7.bean.Bike; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class Cap7MainConfigLifeCycle { @Bean("person") public Person person() { System.out.println("给容器添加person。。。。。"); return new Person("person",20); } @Bean(initMethod = "init",destroyMethod = "destory") public Bike bike(){ return new Bike(); } }
多实例
package com.enjoy.cap7.config; import com.enjoy.cap1.Person; import com.enjoy.cap7.bean.Bike; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Scope; @Configuration public class Cap7MainConfigLifeCycle { @Bean("person") public Person person() { System.out.println("给容器添加person。。。。。"); return new Person("person",20); } @Scope("protoype")// 多实例 @Bean(initMethod = "init",destroyMethod = "destory") public Bike bike(){ return new Bike(); } }
多实例应用场景: 数据库连接池的时候可以用多实例。
生命周期-初始化与销毁2
1, 实现InitalizingBean接口的afterPropertiesSet() 方法,当beanFactory创建号对象,且把bean所有属性设置好之后,会调用这个方法,相当于初始化方法;
2,实现DisposableBean的destory()方法,当销毁时,会把单实例bean进行销毁;
package com.enjoy.cap7.bean; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.stereotype.Component; @Component public class Train implements InitializingBean, DisposableBean { // 当我们的bean 销毁时,调用方法 public Train(){ System.out.println("Train.........constructor......."); } // 当我们的bean属性复制和初始化完成是调用 public void destroy() throws Exception { System.out.println("Train.........destroy......."); } public void afterPropertiesSet() throws Exception { System.out.println("Train.........afterPropertiesSet......."); } }
生命周期-初始化与销毁3
可以使用JSR250 规范定义的(java规范)两个注解来实现
@PostConstruct: 在Bean 创建完成,且属于赋值 完成后进行初始化,属于JDK 规范注解
@PreDestroy : 在Bean 将被移除之前进行通知,在容器销毁之前进行清理工作
提示: JSR 是由JDK 提供的一组规范
package com.enjoy.cap7.bean; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; @Component public class Jeep { public Jeep(){ System.out.println("Jeep......constructor"); } @PostConstruct public void init(){ System.out.println("Jeep..... @PostConstruct......."); } @PreDestroy public void destory(){ System.out.println("Jeep..... @PreDestroy......"); } }
Spring
1, 创建并初始化容器相关的所有processor
2,bean
ping 做的优秀的地方 就是对方法进行拦截, 只用一个注解 processor
public void doOrder(){
A a =new A()
commit();
}
T= cglib.proxyProcess().invoke(bike.class).bike()
通过动态动态代理可以拿到.class 然后直接去调用 类里面的方法
package com.enjoy.cap7.bean; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.stereotype.Component; @Component public class JamesBeanPostProcessor implements BeanPostProcessor { // 传过来的对象就是一个bean // 在初始化调用方法之前做一个后置处理工作 // 什么时候调用它: 在init-method=init 之前调用 @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessBeforeInitializationv ...."+beanName+"......>"+bean); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessAfterInitialization ...."+beanName+"......>"+bean); return bean; } }
6 ,使用BeanPostProcessors 源码初步分析
1,postProcessBeforeInitialization
2,postProcessAfterInitialization
原密码
1.AnnotationConfigApplicationContext
2,this.refresh(); // 刷新并创建容器
3,this.finishBeanFactoryInitialization(beanFactory);
4,beanFactory.preInstantiateSingletons(); // 实例化单实例的bean
5,getBean(beanName);
6,return doGetBean(name, null, null, false);
7,sharedInstance = getSingleton(beanName, () -> {
【return createBean(beanName, mbd, args);】
8,singletonObject = singletonFactory.getObject();
8,Object beanInstance = doCreateBean(beanName, mbdToUse, args);
9,instanceWrapper = createBeanInstance(beanName, mbd, args); // 创建bean
populateBean(beanName, mbd, instanceWrapper); // 创建完bean 之后给属性赋值
exposedObject = initializeBean(beanName, exposedObject, mbd); 再到bean 的初始化
10, invokeInitMethods(beanName, wrappedBean, mbd);
11,((InitializingBean) bean).afterPropertiesSet();
只要使用了 @注解就是一个增强
第四课
贯穿我们的bean 离不开我们的BeanPostProcessor 接口 无非就是对他的实现
对于我们的注解来说
Autowird ---->来说起作用的是整个AutowiredAnnotationBeanPostProcessor 后置处理器; 整个其实也是一个bean 只不过可以控制我们的bean,AutowiredAnnotationBeanPostProcessor 也会注册到IOC 容器中
applyBeanPostProcessorsBeforeInitialization(“Jeep”, beanName);
for (把我们Spring所有的processor 进行遍历){
AutowiredAnnotationBeanPostProcessor
}
bean 在运行时期才可以在到他的类型
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) { Object current = beanProcessor.postProcessBeforeInitialization(result, beanName); if (current == null) { return result; } result = current; } return result; }
@Transactional // 对方法前做一个事务的声明 然后方法后做一个事务提交,做一个切面的处理
@Transactional
method(){}
异步:
AJAX
@Async // 加注解之后 先打印syso(“test 被执行了”) 然就在syso(“被执行了。。。”)
public A(){
syso(“被执行了。。。”)
sleep();
}
public test(){
A()
syso(“test 被执行了”)
}
正在上传…重新上传取消正在上传…重新上传取消正在上传…重新上传取消
@Autowired @Service @Inject
@Quialifar @Primary
2 @Value 属性赋值
1,使用bean.xml 配置文件进行赋值
2, 使用@Value 赋值 : 基本字符赋值, Spring表达式赋值,获取运行环境变量的值;
3, 使用@ Value 从, *properties 取值;
bean.xml ----> location="classpath:/*.properties"
beans.xml -->property="url" value="${}"
@Value 无非就这三种方式
3,@Autowied @Qualifier @Primary 自动装配
什么是自动装配?
spring利用依赖注入(DI),完成对IOC 容器中的各个组件的依赖关系赋值
思考与操作?
1,bean组件加载优先级?
先加载@Autowired 声明的,如果有Qualifier 就去加载指定的Qualifier的bean
2,如果容器中存在两个id相同的bean,会加载那个bean呢?
会覆盖掉前面的 优先加载配置的,然后才扫描包,如果DefaultListableBeanFactory类中,有个属性 allowBeanDefinitionOverriding, 设置为false ,有两个相同id的bean的话就会报错。
3,如何指定装配组件ID进行加载?@Qualifier
@Qualifier("testDao") // 会指定去容器中拿 testDao 这个id的bean
4, 容器加载不存在的bean会出现什么问题?
报错
5,@primary 注解 bean首选如何使用?
@primary 作为首选的,主要的,指定优先级,如果有的话 我先去拿
Spring自动转配的时候默认首选的bean
6,@Autowired @Resource @Inject 区别?
@Autowired @Resource 效果一样的装配bean
@Resource 1,不支持@primary ;2,不支持Autowired false ;3 可能会出现问题; Autowired 有优先级和一些配置更加灵活
@Autowired 用的最多的地方是 controller 层 service 层 dao层
// 可以完成我们的bean 装配
@Inject 她是第三方的一个包 需要引入pom.xml 依赖
也是一个 JSR-330 的一个规范 首先和@Autowired 功能差不多,
支持@primary ,只是没有Autowired 的@Autowired(required = false) 这个是不存在的时候不会报错;
@Inject 使用场景: 有些不是spring项目 可以引入这个包 然后使用注入方式
@Service public class TestService { //@Qualifier("testDao") @Autowired(required = false) // @Inject //@Resource private TestDao testDao; public void println(){ System.out.println(testDao); } }