代码
1、组件
现在很常见的就是不管如何先定义接口,如下所示:
package com.sishuok; public interface Interface { public void sayHello(); }
然后定义实现,真的有必要吗?思考下。
package com.sishuok; public class Impl implements Interface { @Override public void sayHello() { System.out.println("hello"); } }
Bean用于注入Impl,其实此处是错误的,因为定义了接口,应该注入接口的。
package com.sishuok; public class Bean { private Impl impl; public Bean() { } public Bean(final Impl impl) { this.impl = impl; } }
2、需要一个切面
怎么实现无所谓,就是为了生成代理对象,重现问题。
package com.sishuok; public class Aspect { public void before() { System.out.println("==before"); } }
3、 配置文件
<bean id="aspect" class="com.sishuok.Aspect"/> <aop:config> <aop:aspect ref="aspect"> <aop:before method="before" pointcut="execution(* com.sishuok.Impl.*(..))"/> </aop:aspect> </aop:config> <bean id="impl" class="com.sishuok.Impl"/> <bean id="b" class="com.sishuok.Bean"> <constructor-arg name="impl" ref="impl"/> </bean>
配置文件很简单。 一个AOP切面会横切Impl,即生成Impl代理,而Bean会注入Impl。
4、测试类
测试类很简单,只需要加载配置文件即可。
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations={"classpath:spring-config.xml"}) public class BeanIT { @Autowired private Bean bean; @Test public void test() { System.out.println("=hello test"); } }
整段代码很简单,应该能猜到是嘛问题。
抛出的异常
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'b' defined in class path resource [spring-config.xml]: Could not resolve matching constructor (hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)
这个异常让人疑惑,因为它告诉你说可能是构造器的问题,所以可能把我们带坑里看不到真实问题。
主要原因是:
我们实际定义了两个构造器:
1、一个空参的:public Bean()
2、一个带Impl参数的:public Bean(final Impl impl)
如果把第一个构造器删除就会得到真实的异常:
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'b' defined in class path resource [spring-config.xml]: Unsatisfied dependency expressed through constructor argument with index 0 of type [com.sishuok.Impl]: Could not convert constructor argument value of type [$Proxy8] to required type [com.sishuok.Impl]: Failed to convert value of type '$Proxy8 implementing com.sishuok.Interface,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised' to required type 'com.sishuok.Impl'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [$Proxy8 implementing com.sishuok.Interface,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised] to required type [com.sishuok.Impl]: no matching editors or conversion strategy found
很明显是注入问题,见到$Proxy8 我们就能猜到是JDK动态代理(这个在《spring的二次代理原因及如何排查》说过),即它不能转换为实际的com.sishuok.Impl,问题很明显了.
此处还有另一个问题:关于按照构造器参数名注入时,具体参考《【第三章】 DI 之 3.1 DI的配置使用 ——跟我学spring3》中的构造器注入部分。
解决方案
1、要么构造器注入接口,即public Bean(final Interface impl)
2、要么使用CGLIB类代理
总结
1、知道自己使用的是啥编程风格:
- 先定义接口,然后实现;如UserController---->UserService(接口 其实现是UserServiceImpl),这种情况大多数人都使用接口注入即可
- 我喜欢直接定义实现,如UserController--->UserService(实现),因为这是一个模块内部的操作,干嘛定义接口呢?可扩展?想想自己扩展过吗?如果实在想要可扩展我一般是这样:UserApi UserApiImpl 可参考我的es脚手架
2、知道自己使用的啥代理:
- JDK动态代理 还是 CGLIB代理, 做到心中有数,尽量别混用。当然最保险的方式就是使用CGLIB代理。
明确自己的风格,从一而终,不要为了玩玩都用上,Spring已经很庞大且复杂了,,使用Spring出问题最多的就是AOP部分,遇到AOP问题。可参考《请不要再使用低级别的AOP API》
我喜欢
- 给自己使用的无需定义接口;即一个模块内部的都是封装的,定义接口并不会得到很多好处,变过几次实现?? “优先面向接口编程,而非实现” 不是必须,是优先;
- 给朋友(第三方)使用的定义接口;即要公开的功能,因为接口就是个契约,就是沟通用的;
- 优先使用setter注入,除非必要才使用构造器注入;
- 使用CGLIB代理,这样基本不会出现AOP代理注入不了或一些隐晦的问题;
- 优先使用Spring提供的XML标签简化功能定义,如<aop:config>、<task:executor>等,而不要使用低层次API;
- 尽量使用XML风格的事务,而不是注解风格;
- 按照配置的内容分多配置文件存放配置,不要一股脑的放在一起,就像不分包那样;
- 可配置部分(如db数据)还是放到XML中,不要什么都注解;
- 使用Spring profile 或 maven profile分环境测试(如开发环境、测试环境、正式机环境);
官方文档还是要看的,当然刚开始可能比较困难,但是坚持几次以后就轻松了,出问题先看文档,接着翻javadoc,基本能搞定,当然读一读源码对日常开发的调错还是很有帮助的。
相关推荐
深度神经网络是一种目前被广泛使用的工具,可以用于图像识别、分类,物体检测,机器翻译等等。深度学习(DeepLearning)是一种学习神经网络各种参数的方法。因此,我们将要介绍的深度学习,指的是构建神经网络结构,...
postman是一款功能强大的网页调试和模拟发送HTTP请求的Chrome插件,支持几乎所有类型的HTTP请求,操作简单且方便。
架构就是数据库对象的容器。数据库对象是饮料,架构就是杯子,谁拿杯子喝水呢?当然是用户,那么是不是一个用户只能用一个杯子,一个杯子是不是从一而终,只能给一个人用呢?
指向不同类型的指针的区别在于指针类型可以知道编译器解释某个特定地址(指针指向的地址)中的内存内容及大小,而void*指针则只表示一个内存地址,编译器不能通过该指针所指向对象的类型和大小,因此想要通过void*...
把简单重复上级文件和讲话精神看作是贯彻执行,只讲执行的形式,不讲执行的结果,根本达不到贯彻落实的目的。或者脱离本地、本单位的实际情况,教条式的执行。不带头做表率,不深入工作调查研究,做事草率马虎,热...
引用“从一而终” 4. 引用没有 const,指针有 const,const 的指针不可变;5. 引用不能为空,指针可以为空;6. “sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本身(所指向的变量...
中美两国不同的经济发展水平和文化传统使两国的婚姻伦理存在差异。...中美两国的离婚率和离婚原因反映出当婚姻出现问题时,中国家庭会本着"从一而终"的观念尽力挽回,而美国家庭则是用"顺其自然"的态度面对。
我们的服务要求做到无微不至,任何情况下,都要诚恳地对待每一位顾客,服务周到细致,从一而终。 4.竞争对手和自身优势的维持 竞争对手的优势:成立的时间早,经验丰富;规模大;销售渠道广泛;有一大批老顾客。 ...
其实柳猫想要告诉大家,作为一个普通人,对各种信息越是了解的多,认识的越是浅薄,为了增强自己的不可替代性,必须增加自己专业的深度,从一而终。今天,想跟大家分享一下最早也是最简单的一个机器学习模型:感知器...
作者简介:认真且鼓励,从一而终。 技术栈 JavaScript , Vue 2.6 , Bootstrap 4.6 , nodejs 15.x , elementUi 插件 轴距 网络请求 dayjs 日期格式化 ass 样式前置器 加密 散列加密 表示 http服务器框架 ...
VS2017 导入QT开发