blog.csdn.net/pan_junbiao… blog.csdn.net/pan_junbiao…
目录
- 1.基础
- 2.IOC基于xml的配置
- 3.IOC基于注解的配置
- 4.AOP的相关概念
- 6.spring进阶
- 7.消息监听机制
- 8.事物控制与传播行为
- 9.Spring源码
- 10.spring的生命周期
1.bean的覆盖问题
在默认情况下spring允许bean的重名情况出现
当在同一个xml文件下,如果出现了重名的bean,则会报错
在不同的xml文件中出现了重名的bean,则后加载的bean会覆盖前面加载的同名bean
bean的加载过程代码如下
synchronized (this.beanDefinitionMap) {
//从beanDefinationMap中获得beanDefination
Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);
//如果oldBeanDefinition存在,则查看是否允许覆盖,若不存在,则进行bean的实例化
if (oldBeanDefinition != null) {
//如果不允许覆盖,则直接报异常,否则进行覆盖
if (!this.allowBeanDefinitionOverriding) {
throw new BeanDefinitionStoreException(beanDefinition
.getResourceDescription(), beanName,
"Cannot register bean definition ["
+ beanDefinition + "] for bean '"
+ beanName + "': There is already ["
+ oldBeanDefinition + "] bound.");
} else {
if (this.logger.isInfoEnabled()) {
this.logger
.info("Overriding bean definition for bean '"
+ beanName + "': replacing ["
+ oldBeanDefinition + "] with ["
+ beanDefinition + "]");
}
}
} else {
this.beanDefinitionNames.add(beanName);
this.frozenBeanDefinitionNames = null;
}
this.beanDefinitionMap.put(beanName, beanDefinition);
resetBeanDefinition(beanName);
}
所以。如果不允许覆盖,需要将allowBeanDefinitionOverriding设置为false
- 方法一:通过applicationContext的setAllowBeanDefinitionOverriding方法
注意:需要调用refresh重新刷新applicationContext
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("配置文件1.xml");
applicationContext.setAllowBeanDefinitionOverriding(false);
applicationContext.refresh();
2.工厂模式生成bean
工厂模式生成bean,可以通过工厂中方法的返回值生成我们需要的bean
- (一)使用xml注解的工厂模式生成bean
主要使用factory-method标签与factory-bean标签
/**
* 模拟一个静态工厂,创建业务层实现类
*/
public class StaticFactory {
public static IAccountService createAccountService(){
return new AccountServiceImpl();
}
}
<!-- 此种方式是:
使用 StaticFactory 类中的静态方法 createAccountService 创建对象,并存入 spring 容器
id 属性:指定 bean 的 id,用于从容器中获取
class 属性:指定静态工厂的全限定类名
factory-method 属性:指定生产对象的静态方法
-->
<bean id="accountService"
class="com.itheima.factory.StaticFactory"
factory-method="createAccountService"></bean>
/**
* 模拟一个实例工厂,创建业务层实现类
* 此工厂创建对象,必须现有工厂实例对象,再调用方法
*/
public class InstanceFactory {
public IAccountService createAccountService(){
return new AccountServiceImpl();
}
}
<!-- 此种方式是:
先把工厂的创建交给 spring 来管理。
然后在使用工厂的 bean 来调用里面的方法
factory-bean 属性:用于指定实例工厂 bean 的 id。
factory-method 属性:用于指定实例工厂中创建对象的方法。
-->
<bean id="instancFactory" class="com.itheima.factory.InstanceFactory"></bean>
<bean id="accountService"
factory-bean="instancFactory"
factory-method="createAccountService"></bean>
- (二)@Bean注解也可以将一个方法的返回值注册到spring容器中
@Configuration
public class AppConfig {
@Bean
public TransferService transferService() {
return new TransferServiceImpl();
}
}
3.FactoryBean
通过FactoryBean我们可以对一些复杂的bean在注册前进行初始化,或者将一些复杂的bean的创建过程包装起来,给bean的属性设置初始值等
public interface FactoryBean<T> {
T getObject() throws Exception;
Class<T> getObjectType();
boolean isSingleton();
}
实例:
public class MyCarFactoryBean implements FactoryBean<Taxi> {
private String make;
private int year ;
public void setMake(String m){ this.make =m ; }
public void setYear(int y){ this.year = y; }
@Override
public Taxi getObject(){
//模拟复杂bean的构建过程
Taxi taxi = new Taxi();
taxi.setTaxiNmae("factory");
return taxi;
}
@Override
public Class<Car> getObjectType() { return Car.class ; }
@Override
public boolean isSingleton() { return false; }
}
public class Taxi {
private String taxiNmae;
public void setTaxiNmae(String taxiNmae) {
this.taxiNmae = taxiNmae;
}
public void say() {
System.out.println("I am a Taxi..."+taxiNmae);
}
}
xml配置
<bean id = "myCarFactoryBean" class = "com.qunar.spring入门.pojo.MyCarFactoryBean" >
<property name = "make" value ="Honda"/>
<property name = "year" value ="1984"/>
</bean>
<bean id = "car" class = "com.qunar.spring入门.pojo.Car" >
<property name="taxi" ref="myCarFactoryBean"></property>
</bean>
spring会自动的调用getObject方法返回目标对象
4.初始化bean的回调
初始化bean的回调,在spring完成bean的实例化和初始化之后,会自动执行的方法
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User2 {
private Integer userId;
private String name;
private String password;
void printInfo() {
System.out.println("user2");
}
}
(一)通过标签内部的init-method方法指定回调方法
<bean id = "user" class = "com.qunar.spring入门.pojo.User2" init-method="printInfo" ></bean>
(二)实现initializingBean接口,重写afterPropertiesSet方法
public class User2 implements InitializingBean {
private Integer userId;
private String name;
private String password;
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("initializingBean:user2");
}
}
(三)使用@Bean注解中的initMethod属性置顶初始化方法
@Bean(initMethod = "prinfInfo")
public User foo() {
return new User();
}
(四)使用@PostConstruct注解,指定回调方法
@PostConstruct
void printInfo() {
System.out.println("user2");
}
5.销毁bean的回调
(一)通过标签内部的destory-method属性指定销毁方法
<bean id = "user" class = "com.qunar.spring入门.pojo.User2" destory-method="printInfo" ></bean>
(二)通过实现DisposableBean接口,重写destory方法
public class AnotherExampleBean implements DisposableBean {
public void destroy() {
// do some destruction work (like releasing pooled connections)
}
}
(三)在@Bean注解中的destoryMethod属性指定销毁方法
@Bean(destroyMethod = "cleanup")
public Bar bar() {
return new Bar();
}
(四)通过@PreDestory注解指定销毁方法
@PreDestroy
public void cleanup() {
}
6.Bean 继承
Spring bean也可以与java中的继承相似,子类bean可以继承父类bean的属性和方法,也可以重写这些方法
主要是通过 中的 parent 属性来指定父类bean
<bean id="user1" class="com.qunar.spring入门.pojo.User1">
<property name="name" value="user1"></property>
<property name="password" value="user1"></property>
</bean>
<bean id="user2" class="com.qunar.spring入门.pojo.User2" parent="user1">
<property name="name" value="user2"></property>
</bean>
7.方法的注入
主要是lookupMethod与replaceMethod两个标签, 可以对bean的返回结果或者是方法体进行拦截增强
查找方法注入:用于注入方法返回结果,也就是说能通过配置方式替换方法返回结果。即我们通常所说的lookup-method注入。
替换方法注入:可以实现方法主体或返回结果的替换,即我们通常所说的replaced-method注入。
spring方法的注入,主要有两个注解
8.ConversionService
9.BeanPostProcessor
也叫做后置处理器,通过beanPostProcessor可以在bean的实例化和依赖注入之后,进行相关方法的调用或者自定义逻辑的处理
BeanProcessor接口的源码
public interface BeanPostProcessor {
//在自定义的init方法前执行
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
//在自定义的init方法后执行
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
-(一)BeanPostProcessor的使用
/**
* 自定义BeanPostProcessor实现类
* BeanPostProcessor接口的作用是:
* 我们可以通过该接口中的方法在bean实例化、配置以及其他初始化方法前后添加一些我们自己的逻辑
*/
public class MyBeanPostProcessor implements BeanPostProcessor {
/**
* 实例化、依赖注入完毕,在调用显示的初始化之前完成一些定制的初始化任务
* 注意:方法返回值不能为null
* 如果返回null那么在后续初始化方法将报空指针异常或者通过getBean()方法获取不到bena实例对象
* 因为后置处理器从Spring IoC容器中取出bean实例对象没有再次放回IoC容器中
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("before--实例化的bean对象:"+bean+"\t"+beanName);
// 可以根据beanName不同执行不同的处理操作
return bean;
}
/**
* 实例化、依赖注入、初始化完毕时执行
* 注意:方法返回值不能为null
* 如果返回null那么在后续初始化方法将报空指针异常或者通过getBean()方法获取不到bena实例对象
* 因为后置处理器从Spring IoC容器中取出bean实例对象没有再次放回IoC容器中
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("after...实例化的bean对象:"+bean+"\t"+beanName);
// 可以根据beanName不同执行不同的处理操作
return bean;
}
}
public class User3 {
private int id;
private String name;
private String beanName;
public User3(){
System.out.println("User 被实例化");
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("设置:"+name);
this.name = name;
}
public String getBeanName() {
return beanName;
}
public void setBeanName(String beanName) {
this.beanName = beanName;
}
/**
* 自定义的初始化方法
*/
public void start(){
System.out.println("User 中自定义的初始化方法");
}
@Override
public String toString() {
return "User3{" +
"id=" + id +
", name='" + name + '\'' +
", beanName='" + beanName + '\'' +
'}';
}
}
xml的配置,将PostPostPrecessor添加进容器即可
<bean class="com.qunar.spring入门.pojo.User3" id="user3" init-method="start">
<property name="name" value="波波烤鸭" />
</bean>
<!-- 注册处理器 -->
<bean class="com.qunar.spring入门.pojo.MyBeanPostProcessor"></bean>
执行结果:
ser 被实例化
设置:波波烤鸭
before--实例化的bean对象:User3{id=0, name='波波烤鸭', beanName='null'} user3
User 中自定义的初始化方法
after...实例化的bean对象:User3{id=0, name='波波烤鸭', beanName='null'} user3
User3{id=0, name='波波烤鸭', beanName='null'}
也可以设置多个BeanPostProcessor,会默认按照申明的顺序进行调用,也可以实现Ordered接口,实现 getOrder() 方法指定顺序,在Spring机制中可以指定后置处理器调用顺序,通过让BeanPostProcessor接口实现类实现Ordered接口getOrder方法,该方法返回一整数,默认值为 0,优先级最高,值越大优先级越低
public class MyBeanPostProcessor implements BeanPostProcessor,Ordered{
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Override
public int getOrder() {
// TODO Auto-generated method stub
return 10;
}
}
10.三级缓存
11.循环依赖
12.@Autowired与@Resource的区别
13.spring cache缓存
14.spring事务的使用
15.bean的生命周期
16.BeanFactory与ApplicationContext的区别
cloud.tencent.com/developer/a…
17.内部bean
当一个bean仅被用作另一个bean的属性时,它能被声明为一个内部bean,为了定义inner bean,在Spring 的 基于XML的 配置元数据中,可以在 或 元素内使用 元素,内部bean通常是匿名的,它们的Scope一般是prototype。
代码示例:
<bean id="person2" class="com.itdjx.spring.dependency.injection.Person">
<property name="name" value="李玉"/>
<property name="age" value="23"/>
<property name="sex" value="女"/>
<property name="car" >
<bean class="com.itdjx.spring.dependency.injection.Car">
<constructor-arg value="Ferrari" index="0"/>
<constructor-arg value="Italy" index="1"/>
<constructor-arg value="22500000" type="double"/>
</bean>
</property>
</bean>