spring核心两大核心内容为ioc和aop。
本章节讲ioc的概念、作用和使用方式。
ioc简单介绍:
概念:控制反转,把对象创建和对象之间的调用过程,交给Spring管理
目的是降低耦合
底层原理:xml解析、工厂模式、反射
.过程:
- 1 xml解析得到类的全路径
ApplicationContext applicationContext =new
ClassPathXmlApplicationContext("bean.xml");
- 2 通过反射创建对象
- 3 通过工厂类返回
User user =applicationContext.getBean("user",User .class);
Ioc思想基于ioc容器完成,ioc容器本质上就是对象工厂。
spring提供ioc容器实现两种方式:(两个接口)
1.BeanFactory:
Ioc容器基本实现,是Spring内部的使用接口,不提供开发人员进行使用
ps:加载配置文件的时候不会创建对象,在获取对象使用才会去创建对象
2.ApplicationContext:
有两个实现类:不同在于FileSystemXmlApplicationContext是传绝对路径,ClassPathXmlApplicationContext是传在项目中的相对路径。
ApplicationContext applicationContext =new
ClassPathXmlApplicationContext("bean.xml");
User user =applicationContext.getBean("user",User .class);
ioc管理对象:(指的是创建对象和注入属性)
1.基于xml配置文件
2.基于注解方式
基于xml方式:
1.基于xml方式创建对象
使用bean标签 id:唯一属性 class:类全路径
<bean id="user" class="com.wsl.spring.dao.UserDao" ></bean>
2.基于xml方式注入属性
DI:依赖注入,是ioc注入属性的具体实现
2.1.基于set注入 :使用property注解
<bean id="user" class="com.wsl.spring.pojo.User" >
<property name="name" value="小红"></property>
<property name="age" value="11"></property>
</bean>
2.2.基于有参构造器注入
<bean id="user" class="com.wsl.spring.pojo.User" >
<constructor-arg index="0" value="小绿"></constructor-arg>
<constructor-arg index="1" value="22"></constructor-arg>
</bean>
如果set注入和构造器注入都写了,先执行构造器,再执行set
2.3.p命名空间注入
可以简化基于xml方式注入
1.在配置文件中添加p命名空间
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
**xmlns:p="http://www.springframework.org/schema/p"**
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
2.使用p注入
<bean id="user" class="com.wsl.spring.pojo.User"
p:age="33" p:name="小兰">
</bean>
ps:特殊符号处理
1.转义
2.CDATA格式
bean
在Spring中,那些组成应用程序的主体及由Spring IoC容器所管理的对象,被称之为bean。简单地讲,bean就是由IoC容器初始化、装配及管理的对象
spring中有两种bean,一种是普通bean,一种是工厂bean FactoryBean (不是beanEactory 不一样的)
普通bean:在配置文件中定义bean类型就是返回类型
工厂bean:在配置文件中定义bean类型可以和返回类型不一样
Step1:创建类,让这个类作为工厂bean,实现接口FactoryBean
Step2:实现接口的方法,在实现的方法中定义返回的类型。
bean的作用域:
spring中默认是单实例的,在加载spring配置文件的时候就会创建单实例对象。
设置为prototype的时候,在调用getBean的时候才会创建多实例对象。
bean的生命周期:
bean对象从创建到销毁的过程。
1.通过构造器创建bean实例
2.为bean的属性设置值和对其他bean的引用(调用set)
3.实现后置处理器,在初始化前做一些工作
4.调用bean的初始化(需要配置初始化方法)init-method配置
5.实现后置处理器,在初始化后做一些工作
6.使用bean
7.当容器关闭,调用bean的销毁方法(需要配置销毁的方法)destroy-method配置
<bean id="user" class="com.wsl.spring.pojo.User"
p:age="33" p:name="小兰" init-method="init" destroy-method="destory">
</bean>
注解方式
@PostConstruct
protected void init() {
System.out.println("init();");
}
@PreDestroy
protected void destory() {
System.out.println("destory();");
}
后置处理器 :实现 BeanPostProcesser 接口 ,可以在初始化前后进行一些处理工作。
外部文件配置bean
1.创建文件jdbc.properties
#============================#
#===== Database sttings =====#
#============================#
#oracle database settings
#jdbc.type=oracle
#jdbc.driver=oracle.jdbc.driver.OracleDriver
#jdbc.url=jdbc:oracle:thin:@127.0.0.1:1521:orcl
#jdbc.username=jeesite
#jdbc.password=123456
2.引入文件并注入bean
<!-- 加载配置属性文件 -->
<context:property-placeholder ignore-unresolvable="true" location="classpath:jdbc.properties" />
<!-- bean设置 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<!-- 数据源驱动类可不写,Druid默认会自动根据URL识别DriverClass -->
<property name="driverClassName" value="${jdbc.driver}" />
<!-- 基本属性 url、user、password -->
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<!-- 配置初始化大小、最小、最大 -->
<property name="initialSize" value="${jdbc.pool.init}" />
<property name="minIdle" value="${jdbc.pool.minIdle}" />
<property name="maxActive" value="${jdbc.pool.maxActive}" />
<!-- 配置获取连接等待超时的时间 -->
<property name="maxWait" value="60000" />
</bean>
基于注解方式:
1.开启组件扫描
component-scan 指定注解扫描包
<context:component-scan base-package="com.wsl"></context:component-scan>
或者直接使用@ComponentScan注解
2.在需要扫描的类上面加注解
@Component
@Component("user")
// 相当于配置文件中 <bean id="user" class="当前注解的类"/>
@Component三个衍生注解
为了更好的进行分层,Spring可以使用其它三个注解,功能一样,目前使用哪一个功能都一样。
@Controller:controller层
@Service:service层
@Repository:dao层
3.基于注解实现属性注入
1.@Autowired
在使用@Autowired时,首先在容器中查询对应类型的bean
如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据
如果查询的结果不止一个,那么@Autowired会根据名称来查找。
如果查询的结果为空,那么会抛出异常。解决方法时,使用required=false
2.@Qualifier
@Autowired是根据类型自动装配的,加上@Qualifier则可以根据byName的方式自动装配
@Qualifier不能单独使用。
3.@Resource
**@Autowired与@Resource异同:
1、@Autowired与@Resource都可以用来装配bean。都可以写在字段上,或写在setter方法上。
2、@Autowired默认按类型装配(属于spring规范),默认情况下必须要求依赖对象必须存在,
如果要允许null 值,可以设置它的required属性为false,如:@Autowired(required=false)
,如果我们想使用名称装配可以结合@Qualifier注解进行使用
3、@Resource(属于J2EE复返),默认按照名称进行装配,名称可以通过name属性进行指定。
如果没有指定name属性,当注解写在字段上时,默认取字段名进行按照名称查找,如果注解写在
setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。
但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
它们的作用相同都是用注解方式注入对象,但执行顺序不同。@Autowired先byType,@Resource先byName。**
其他注解:
@Value
用这个注解注入属性
1.直接写值
2.可以写SpEl #{ }
3 ${ } 格式 可以取出配置文件中的值 但需要先用注解@PropertySource(“os.properties”)取到配置文件
、在运行环境变量里面的值
@Value("小红")
private String name;
@Value("#{20-2}")
private int age;
// 相当于配置文件中 <property name="name" value="小红"/>
@Value(${os.name}) //需要在类上面使用PropertySource注解
private String os;
// 类似xml中先用<context:property-placeholder >引入外部文件 再用${}取值
@Scope
指定bean作用域:singleton prototype request session
@LazyBean
是针对单实例bean,默认情况下单实例bean是在容器加载的时候创建的。
而懒加载在容器加载时候不创建bean,在第一次使用bean的时候才会创建和初始化。
@Conditional
按照一定的条件进行判断,满足条件向容器注册bean。
可用于类和方法
编写两个类,分别实现Condition接口。
//linux环境下返回true
public class LinuxCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String os = context.getEnvironment().getProperty("os.name");
return os.contains("Linux");
}
}
//windows环境下返回true
public class WindowsCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String os =context.getEnvironment().getProperty("os.name");
return os.contains("Windows");
}
}
然后在需要判断的bean上加注解@Conditional和用于判断的类名,在满足该类实现的matches方法时,会向容器注册该bean,否则不注册。也可以用于类上面,作用于该类所有的bean。
@Configuration
public class BeanConfig {
@Conditional(WindowsCondition.class)
@Bean("windows-张三")
public User getUser(){
return new User("windows-张三",11);
}
@Conditional(LinuxCondition.class)
@Bean("linux-张三")
public User getUser1(){
return new User("linux-张三",11);
}
}
@import
快速导入一个组件
@PropertySource
引入外部文件 类似xml中先用<context:property-placeholder >
@Primary
在spring 中使用注解,常使用@Autowired, 默认是根据类型Type来自动注入的。但有些特殊情况,对同一个接口,可能会有几种不同的实现类,而默认只会采取其中一种的情况下 @Primary 的作用就出来了,告诉spring 在犹豫的时候优先选择哪一个具体的实现。
@Inject
1、@Inject是JSR330 (Dependency Injection for Java)中的规范,需要导入javax.inject.Inject;实现注入。
2、@Inject是根据类型进行自动装配的,如果需要按名称进行装配,则需要配合@Named;
3、@Inject可以作用在变量、setter方法、构造函数上。
a、将@Inject可以作用在变量、setter方法、构造函数上,和@Autowired一样
b、@Named
@Named(“XXX”) 中的 XX是 Bean 的名称,所以 @Inject和 @Named结合使用时,自动注入的策略就从 byType 转变成 byName 了。
@Profile
指定这个bean在该环境下才能注册到容器中去
自动装配是使用spring满足bean依赖的一种方法
spring会在应用上下文中为某个bean寻找其依赖的bean。
Spring中bean有三种装配机制,分别是:
在xml中显式配置;
在java中显式配置;
隐式的bean发现机制和自动装配。
自动装配:根据指定装配规则(属性名称或者属性类型),将匹配的属性值进行注入。
Spring的自动装配需要从两个角度来实现,或者说是两个操作:
组件扫描(component scanning):spring会自动发现应用上下文中所创建的bean;
自动装配(autowiring):spring自动满足bean之间的依赖,也就是我们说的IoC/DI;
组件扫描和自动装配组合发挥巨大威力,使得显示的配置降低到最少。
总结:
给容器中注册组件:
1.包扫描+组件标注注解(@Component @Controller等) 适用于自己编写的类
2.@Bean 用于导入的第三方包里的组件
3.@import 快速导入一个组件
实现ImportSelector 返回需要导入的组件全类名数组
ImportBeanDefinitionRegistrar 手动注册Bean
4.实现Factory接口(工厂bean)
默认获取到的是工厂bean调用getObject创建的对象
要获取工厂bean的本事,需要在id前加一个&符号
5.自定义组件想要使用Spring底层的一些组件,可以实现XXXAware接口注入;每一个XXXAware都有对应的XXXProcesser,为自定义类注入对应Aware。
指定初始化和销毁方法:
1.bean标签的init-method和destory-method
2.bean class实现InitializingBean(定义初始化方法),
实现DisposableBean接口(定义销毁方法)
3.JSR250规范中的@PostConstruct 初始化
@PreDestory 销毁
4。后置处理器 BeanPostProcessor接口
两个方法分别在初始化前后工作