Spring解决方法

来源:互联网 发布:兰州理工大学 软件学院 编辑:程序博客网 时间:2024/06/07 12:04

读properties中文乱码

  在config类中,使用@PropertySource注解引入properties时,设置读取方式与properties的编码方式一致,需要Spring4.3以上版本。PropertySource说明
  @PropertySource(value = "environment.properties",encoding = "UTF-8")

AOP拦截内部调用的方法

  参考http://blog.csdn.net/dream_broken/article/details/72911148,目前我只使用了第一种,设置一个全局变量applicationContext,然后调用。没有使用第二种方式,是因为据说在多线程中会有问题,参考https://www.cnblogs.com/intsmaze/p/5206584.html。

2.1 方案一–从beanFactory中获取对象
刚刚上面说到controller中的UserService是代理对象,它是从beanFactory中得来的,那么service类内调用其他方法时,也先从beanFacotry中拿出来就OK了。
public void insert02(User u){
getService().insert01(u);
}
private UserService getService(){
return SpringContextUtil.getBean(this.getClass());
}
2.2 方案二–获取代理对象
private UserService getService(){
// 采取这种方式的话,
//@EnableAspectJAutoProxy(exposeProxy=true,proxyTargetClass=true)
//必须设置为true
return AopContext.currentProxy() != null ? (UserService)AopContext.currentProxy() : this;
}
如果aop是使用注解的话,那需要@EnableAspectJAutoProxy(exposeProxy=true,proxyTargetClass=true),如果是xml配置的,把expose-proxy设置为true。
2.3方案三–将项目转为aspectJ项目
将项目转为aspectJ项目,aop转为aspect 类。具体就不写了
2.4 方案四–BeanPostProcessor
通过BeanPostProcessor 在目标对象中注入代理对象,定义InjectBeanSelfProcessor类,实现BeanPostProcessor。也不具体写了

多线程与单例

一般的单例

使用@Autowired

  在单线程情况下,若类A和类B均使用@Autowired方式装配类Z,且类Z使用单例模式时,多个类可以包含同一个类的同一个对象,如下图:
单例模式
  从地址可以看出,两个类中包含的是同一个对象实例,如下图:
这里写图片描述

使用同一个ApplicationContext的getBean()方法

  若使用同一个ApplicationContext对象,当类A和类B使用相同的ApplicationContext对象的getBean()方法时,获取的类A和类B对象中的类Z是相同的。装配代码如下图:
这里写图片描述
  类A和类B所包含的类Z的地址如下图,可以看出使用的是同一个对象:
这里写图片描述

使用不同的ApplicationContext的getBean()方法

  当使用了多个ApplicationContext对象,当类A和类B使用不同的ApplicationContext对象的getBean()方法时,获取的类A和类B对象中的类Z是不同的。装配代码如下图:
这里写图片描述
  类A和类B所包含的类Z的地址如下图,可以看出使用的不是同一个对象:
这里写图片描述
  原因如下,稍有修改(原文http://blog.163.com/axuandebin@126/blog/static/118777042009426105612512/)

  每次通过new创建一个ApplicationContext容器,都会执行refresh方法,看源代码了解到这个refresh方法会重新加载配置文件,并且这个创建的容器对象持有一个所有singleton类型bean的map集合,从而实现单例,而且这个map对象的生命周期和容器对象的生命周期是一样的 。
  如果我们每次都通过new一个容器对象,那么每次都要重新加载配置文件,都要重新生成这个singleton bean的集合,这样所谓的单例就失去了意义 。
  在实际的应用中,应该先创建好一个ApplicationContext容器对象,把它保存到某一个地方,在需要这个容器的时候取来用即可。一般可以放在程序最初启动的位置。
  在web应用开发中,我们可以将ApplicationContext容器的启动放在web容器的初始化中实现,这样Spring容器就存放于web容器(servletContext)当中,应用时取出即可。
  而在普通的应用程序中,就需要客户化的代码来实现,最简单的方式就是用一个单例类来封装这个ApplicationContext容器
  用户使用spring配置了N多个Bean. 在web中,spring的bean的获得,常常需要 ApplicationContext对象,或WebApplicationContextUtils类,这些都需要用户的 代码在spring的管理之内,脱离了spring的管理范围,尽管这些bean在你的工程都存在, 但是你却无法访问。

多线程与单例

  现有C类、D类(例如实现事件的监听等功能),各自用新的线程启动成员A和B,而A、B又都包含Z,类C和类D均采用getBean的方式装配类A和类B的对象,预期结构如下图:
这里写图片描述
  类C的装配代码:
这里写图片描述
  类D的装配代码:
这里写图片描述
  类C调试时的情况:
这里写图片描述
  类D调试时的情况:
这里写图片描述
  从上面两个调试的图中可以看出,类A和类B指向了不同的类Z对象,虽然采用SPRING的方式,类Z默认是单例的,但是这里仍然出现了两个不同的地址。实际结构如下图:
这里写图片描述
  为什么会导致这种破坏了单例的情况,我还不清楚,目前采用的解决方法是将类Z中的全部变量都设置为static,使类Z的所有对象都使用同样的变量。现在需要进一步找资料查明问题的原因。
  20171203找到原因了,参考前文“使用不同的ApplicationContext的getBean()方法”一节。

原创粉丝点击