小菜鸟学习spring,最近在啃 Spring IN ACTION ,中文版书名为spring实战,本书被大多数人点赞和好评。为了提高学习效果,特此做一个简单的笔记以便温习回顾,如有错误或者您有更好的建议与意见烦请指正指导。
报错信息摘要如下:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.lujx.concert.test.TestAudience':
Unsatisfied dependency expressed through field 'magicShow'; nested exception is org.springframework.beans.factory.BeanNotOfRequiredTypeException:
Bean named 'magicShow' is expected to be of type 'org.lujx.concert.test.MagicShow' but was actually of type 'com.sun.proxy.$Proxy25'
Caused by: org.springframework.beans.factory.BeanNotOfRequiredTypeException:
Bean named 'magicShow' is expected to be of type 'org.lujx.concert.test.MagicShow' but was actually of type 'com.sun.proxy.$Proxy25'
报错信息来自一个spring的AOP应用的一个demo,结构如下图
其中,Performance是一个接口,Audience是一个切面类,定义了几个切面逻辑,ConcertConfig.java是配置类,在测试包里,MagicShow是Performance接口的实现类;
ConcertConfig.java源码如下,可以看到,配置中启用了AspectJ自动代理和组件扫描,并且以java装配的方式注入了切面类bean
package org.lujx.concert;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@ComponentScan //启动spring组件扫描
@EnableAspectJAutoProxy //启动AspectJ自动代理
public class ConcertConfig {
//使用java装配方式注入bean
@Bean
public Audience audience(){
return new Audience();
}
}
测试类代码如下。
package org.lujx.concert.test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.lujx.concert.ConcertConfig;
import org.lujx.concert.Performance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class) //使用spring单元测试
@ContextConfiguration(classes=ConcertConfig.class) //引入配置类
public class TestAudience {
// 定义接口实现类。由于JDK动态代理不支持类注入,所以程序在此处抛出异常
@Autowired
private MagicShow magicShow;
@Test
public void testPointCut(){
magicShow.perform();
}
}
可以看到,测试类中注入了一个接口实现类,由于spring的代理机制,JDK的动态代理不支持类注入,只支持接口注入,所以解决这个异常的方法有两种:
第一种:改类注入为接口注入,即
// 定义接口实现类。由于JDK动态代理不支持类注入,所以程序在此处抛出异常
//@Autowired
//private MagicShow magicShow;
// 使用接口注入
@Autowired
private Performance magicShow;
第二种,设置ASpectJ自动代理属性,即ConcertConfig.java 文件的注解
//@EnableAspectJAutoProxy
//设置proxyTargetClass属性,可解决JDK动态代理类注入抛出的BeanNotOfRequiredTypeException异常
@EnableAspectJAutoProxy(proxyTargetClass=true) //启动AspectJ自动代理
特此记录,以便参考。
参考资料:
https://blog.csdn.net/jyp360/article/details/70215002
https://blog.csdn.net/u014308482/article/details/53033847
PS:附上其他几个类的源代码
package org.lujx.concert;
public interface Performance {
void perform();
}
package org.lujx.concert;
import org.apache.log4j.Logger;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import net.bytebuddy.asm.Advice.This;
@Aspect
public class Audience {
private Logger LOGGER=Logger.getLogger(This.class);
//定义切入点
@Pointcut("execution(* org.lujx.concert.Performance.perform(..))")
public void performance(){ }
@Before("performance()")
public void silenceCellPhone(){
LOGGER.info("Silence The CellPhone");
}
@Before("performance()")
public void takeSeats(){
LOGGER.info("Taking Seats");
}
@AfterReturning("performance()")
public void applause(){
LOGGER.info("CLAP! CLAP! CLAP!!");
}
@AfterThrowing("performance()")
public void demandRefund(){
LOGGER.info("Demanding a refund");
}
}
package org.lujx.concert.test;
import org.apache.log4j.Logger;
import org.lujx.concert.Performance;
import org.springframework.stereotype.Component;
import net.bytebuddy.asm.Advice.This;
@Component
public class MagicShow implements Performance{
private Logger LOGGER=Logger.getLogger(This.class);
public void perform() {
LOGGER.warn("the singer has started to singing !");
return;
}
}