Spring动态代理后,自动注入被代理的原对象为什么会报错?

yuxian_li 2019-11-10 08:00:35
这是service接口

public interface AccountService {
public List<Account> findAll();
}

这是service接口的实现类

@Service("accountService")
public class AccountServiceImpl implements AccountService {
@Autowired
AccountDao accountDao;
@Override
public List<Account> findAll() {
System.out.println("业务层,查询所有账户信息。。。");
return accountDao.findAll();
}
}


这是controller方法

@Controller
@RequestMapping("/account")
public class AccountController {


@Autowired
private AccountServiceImpl accountService1;


@RequestMapping("/findAll")
public String findAll(){
System.out.println("表现层--AccountController.findAll()");

List<Account> list = accountService1.findAll();
for(Account a:list){
System.out.println(a);
}
return "success";
}
}

在spring中对service的实现类(AccountServiceImpl)进行声明式事务控制,报错,报错核心信息是
Bean named 'accountService' is expected to be of type 'com.service.impl.AccountServiceImpl' but was actually of type 'com.sun.proxy.$Proxy24'
找到原因是spring的事务控制是对AccountServiceImpl进行基于接口的动态代理,将controller中的自动注入类型改为

@Autowired
private AccountService accountService1;

即可。那么我就很奇怪,动态代理的原对象肯定也是存在的,为什么自动注入原对象类型会报错呢?
而且报错的信息除了注入失败以外,最主要的还是spring容器中id为accountService的bean类型本应该为AccountServiceImpl类型。spring是怎么知道bean对象原本类型的?
...全文
174 点赞 收藏 5
写回复
5 条回复
=PNZ=BeijingL 05月17日
jdk动态代理是利用反射机制生成一个实现代理接口的匿名类,代理的是接口

@Autowired
private AccountServiceImpl accountService1; //AccountServiceImpl 这里是实现类
这里应该写成
private AccountService accountService1;
回复 点赞
其实楼主记住这句话就可以了 --> 根据类型获取bean:有接口根据接口类型获取bean,没有接口根据本身类型获取bean。 简单的讲解一下: 目标类被切面后,需要根据它实现的接口类型从容器中获取bean,而不是它(实现类)本身。 容器中保存的是代理对象,代理对象也是这个接口类型。因为代理类也会去实现,实现类所实现的接口。这时代理对象和目标对象唯一产生关联的地方,他们实现了同一个接口。 你可以尝试获取目标类对象的类型,他的真实类型就是一个代理($Proxy)。我们拿着这个代理对象为什么可以调用接口中的方法呢?就是因为代理对象也实现了目标类所实现的接口。
回复 点赞
dkwuxiang 2019年11月11日
Spring 动态代理默认使用的是jdk动态代理 JDK动态代理的原理是根据定义好的规则,用传入的接口创建一个新类,所以只能用接口引用指向代理,而不能用传入的类引用执行动态类。 例如是这个格式: public class $Proxy1 extends Proxy implements 传入的接口{} 如果想直接注入实现类的话,可以配置 <aop:aspectj-autoproxy proxy-target-class="true"/> 使用cglib代理; cglib采用的是用创建一个继承实现类的子类
回复 点赞
土豆是我的最爱 2019年11月11日
你controller层的注入不应该是这么写么
@Autowired
    private AccountService accountService
回复 点赞
亦夜 2019年11月11日
@Autowired会自动进行类型匹配,但是你指定了bean的名称,需要再加上@Qualifier注解并指定名称就行了,或者直接加一个@Resources注解指定名称就行了,至于为什么找不到,仔细去看一下@Autowired是怎么进行匹配的就知道了
回复 点赞
发动态
发帖子
Java EE
创建于2007-09-28

3.7w+

社区成员

22.5w+

社区内容

J2EE只是Java企业应用。我们需要一个跨J2SE/WEB/EJB的微容器,保护我们的业务核心组件(中间件),以延续它的生命力,而不是依赖J2SE/J2EE版本。
社区公告
暂无公告