SpringAOPのプロキシ化の仕組みには
JDK dynamic proxyとCGLIBという二つの仕組みがあるんですが(デフォルトはJDK dynamic proxy)
JDK dynamic proxyでProxy化されたbeanのインスタンスを直接実装クラス指定でAutowired出来ない仕様らしいです。
※この辺が参考になりました
spring - @Override and @Transactional annotations - Stack Overflow
spring - AspectJ and NoSuchBeanDefinitionException at least 1 bean which qualifies as autowire candidate for this dependency - Stack Overflow
なぜそういう仕様なのか?(の考察)
上記記事によると、インターフェースを介さないメソッドをProxy化する場合のみ
CGLIB proxyingを使いましょうというのがSpringAOPのポリシーらしいです。
それを鑑みて、UserDaoをProxy化したbeanはUserDaoImplではないという判断になっているのではないでしょうか?
CGLIBにした場合の弊害
proxy-target-class="true"でCGLIBに強制した場合、実装クラスに対するAutowiredは上手くいくんですが
今度はProxyingの対象クラスが多いとOOMエラーになってしまうという現象も発生しました。
(JDK〜の場合は起こらない。詳細は未調査)
今回の結論
SpringAOPを使う時は基本的にはJDK dynamic proxyでインターフェースに対してプログラミングするのがよさそう。
例
Javaのコード
@Component public class UserDaoImpl implements UserDao { public void save(User user) { // do something } } @Service public class SampleService { // これはダメ //@Autowired //UserDaoImpl userDaoImpl; @Autowired UserDao userDao; } @Aspect public class DaoAspect { @Pointcut("execution(public void com.kamatama41.dao.*.*(..))") public void executeAnyDaoMethod() {} @AfterThrowing(pointcut="executeAnyDaoMethod()", throwing = "ex") public void doSomething(DaoException ex) throws Throwable { System.out.println("Dao error!!!!"); } }
xml
<context:annotation-config /> <!-- JDK dynamic proxyの場合 --> <aop:aspectj-autoproxy/> <!-- CGLIBの場合 --> <!--<aop:aspectj-autoproxy proxy-target-class="true"/>--> <bean id="daoAspect " class="com.kamatama41.aspect.DaoAspect " />
発生する例外の例
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.kamatama41.UserDaoImpl com.kamatama41.service.SampleService.userDaoImpl; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.kamatama41.UserDaoImpl] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:506) at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:284) ... 14 more