Spring深度解析
Spring应用1
XML配置中的手动注入方式
`
@Service
public class TestService {
MXService mXService;
public MXService getMxService() {
return mXService;
}
public void setMXService(MXService mxService) {
this.mXService = mxService;
}
}`
在XML配置文件中基于要相应的为MXService进行手动注入配置:
<bean name="TestService" class="com.abc.TestService">
<property name="MXService"> 注意这里的要和set方法名后的一样
<ref bean="MXService"></ref>
</property>
</bean>
<bean name="MXService" class="com.abc.service.MXService"></bean>
这种方式称为手动注入方式,较为复杂
XML配置中自动装配
根据官网文档,XML中的Autowiring Modes分为四种,no,byName,byType,constructor
·注意这个概念仅仅针对于XML的配置方式,如果为javaConfig方式进行配置则没有该装配模型。
-
@Autowired注解
现根据类型找,找不到再根据名字找,其实这不是一种自动注入模型,如果是的话那么一种方式找不到就会报错,这也是手动装配的一种,在源码中的体现为并不对AUTO_XXX进行判断。 -
XML开启自动装配
<beans xmlns="http://www.springframework.org/schema/beans" ....... default-autowire="byName" >
· 值得注意的是,在byType时只要有set方法就可以,set后面的名字跟什么无所谓,但是当byName时,set方法后面跟的名字就必须为XML中给这个要被注入的Bean的BeanName。并且根据设定的方式找不到就找不到了,不会再根据另一种方式寻找。
@Autowired注解和@Resource有什么区别
首先每个地方都会介绍:@Autowired先根据type找,再根据name找、@Resouce反之。
不同之处在于@Autowired是spring包下面的,@Resource是javax包下面的。
并且@Autowired的处理经过AutowiredAnnotationBeanPostProcessor,
@Resource是由CommonAnnotationBeanPostrProcessor处理的。
两个类实现同一个接口从而XML中byType报错
在XML中byType自动装配时如果两个Bean类型一样就不知道装什么了,直接报错
- 但是@Autowired会根据要注入的名字来进行寻找,并且不需要set方法
`
public class TestService {
@Autowired
MX MXService2;
public MX getMxService() {
return MXService2;
}
public void setMXService(MX mxService) {
this.MXService2 = mxService;
}`
此时根据名字“MXService2”找到了MXService2而不是MXService1来进行注入
@Lookup注解
在使用Spring时,可能会遇到这种情况:一个单例的Bean依赖另一个非单例的Bean。如果简单的使用自动装配来注入依赖,就可能会出现一些问题,如下所示:
单例的Class A
@Component
public class ClassA {
@Autowired
private ClassB classB;
public void printClass() {
System.out.println("This is Class A: " + this);
classB.printClass();
}
}
非单例的Class B
@Component
@Scope(value = SCOPE_PROTOTYPE)
public class ClassB {
public void printClass() {
System.out.println("This is Class B: " + this);
}
}
这里Class A采用了默认的单例scope,并依赖于Class B, 而Class B的scope是prototype,因此不是单例的,这时候跑个测试就看出这样写的问题:
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = {ClassA.class, ClassB.class})
public class MyTest {
@Autowired
private ClassA classA;
@Test
public void simpleTest() {
for (int i = 0; i < 3; i++) {
classA.printClass();
}
}
}
输出的结果是:
This is Class A: ClassA@282003e1
This is Class B: ClassB@7fad8c79
This is Class A: ClassA@282003e1
This is Class B: ClassB@7fad8c79
This is Class A: ClassA@282003e1
This is Class B: ClassB@7fad8c79
可以看到,两个类的Hash Code在三次输出中都是一样。Class A的值不变是可以理解的,因为它是单例的,但是Class B的scope是prototype却也保持Hash Code不变,似乎也成了单例?
产生这种的情况的原因是,Class A的scope是默认的singleton,因此Context只会创建Class A的bean一次,所以也就只有一次注入依赖的机会,容器也就无法每次给Class A提供一个新的Class B。
不那么好的解决方案
要解决上述问题,可以对Class A做一些修改,让它实现ApplicationContextAware。
@Component
public class ClassA implements ApplicationContextAware {
private ApplicationContext applicationContext;
public void printClass() {
System.out.println("This is Class A: " + this);
getClassB().printClass();
}
public ClassB getClassB() {
return applicationContext.getBean(ClassB.class);
}
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
这样就能够在每次需要到Class B的时候手动去Context里找到新的bean。再跑一次测试后得到了以下输出:
This is Class A: com.devhao.ClassA@4df828d7
This is Class B: com.devhao.ClassB@31206beb
This is Class A: com.devhao.ClassA@4df828d7
This is Class B: com.devhao.ClassB@3e77a1ed
This is Class A: com.devhao.ClassA@4df828d7
This is Class B: com.devhao.ClassB@3ffcd140
可以看到Class A的Hash Code在三次输出中保持不变,而Class B的却每次都不同,说明问题得到了解决,每次调用时用到的都是新的实例。
但是这样的写法就和Spring强耦合在一起了,Spring提供了另外一种方法来降低侵入性。
@Lookup
Spring提供了一个名为@Lookup的注解,这是一个作用在方法上的注解,被其标注的方法会被重写,然后根据其返回值的类型,容器调用BeanFactory的getBean()方法来返回一个bean。
@Component
public class ClassA {
public void printClass() {
System.out.println("This is Class A: " + this);
getClassB().printClass();
}
@Lookup
public ClassB getClassB() {
return null;
}
}
可以发现简洁了很多,而且不再和Spring强耦合,再次运行测试依然可以得到正确的输出。
被标注的方法的返回值不再重要,因为容器会动态生成一个子类然后将这个被注解的方法重写/实现,最终调用的是子类的方法。
原文地址:https://www.cnblogs.com/moxi-moxi/p/15148092.html
- 如何做一个小程序口令红包功能
- 使用思维导图,优雅的完成自己的代码
- 移动端布局攻略
- nginx反向代理https网站 并实现网站的注册和登录功能
- 通过nginx GeoIP模块 限制某些国家地区访问网站
- CDN加速下通过nginx获取网站访客真实ip
- linux centos7服务器使用密钥登录ssh同时禁止root密码登录
- linux nginx服务器安装verynginx防止CC攻击
- linux nginx安装HttpGuard防止CC攻击
- wordpress您的主机禁用了mail()函数 SMTP邮件通知解决方法
- 我的编程之路:知识管理与知识体系
- UTF-8 为什么会比 UTF-16 浪费?
- 码农也要学算法
- 19 个常用的 JavaScript 简写方法
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- Spark SQL 小文件问题处理
- vue常用的修饰符有哪些?
- 在 ASP.NET WebAPI 中使用 DataAnnotations 验证数据
- CSS简笔画:纯CSS绘制一艘邮轮
- NHibernate 多对多映射的数据更新
- 使用 AngularJS 的 $resource 连接 WebAPI Controller
- CentOS7.8下编译muduo库找不到Boost库报错的解决方法
- 使用 OWIN 搭建 OAuth2 服务器
- Hive on spark下insert overwrite partition慢的优化
- 系统学习Lambda表达式
- 一文搞懂 Flink Kafka Consumer 类两阶段提交
- 在 Nowin 下运行 ASP.NET 5 Beta 2
- Bytom侧链Vapor源码浅析-节点出块过程
- Kubernetes Pod OOM 排查日记
- Netty之旅:你想要的NIO知识点,这里都有!