Shiro Realm @Autowired 注入失敗的問題
最近在折騰Shiro這個框架,在折騰的過程中遇到一個問題,怎麼都解決不了,最後稀裡糊塗地問題就解決了。原因就在於@Autowire和@Resource這兩個註解的問題,平時這兩個註解都是可以互換的,但是在Shiro中遇到的這個問題,@Autowire與@Resource就有區別了。
瞭解Shiro的都知道,使用Shiro的時候需要自己定義Realm,通過自己定義的Realm對登入進行驗證和授權。在使用者登入的時候,使用Shiro進行驗證的時候,肯定是需要從資料庫中去查詢響應的使用者表,將賬號密碼進行對比驗證,所有在我們自己定義的Realm中,需要與資料進行連線。因為我使用的是SpringMVC+JPA的框架,所以我直接在自己定義的Realm中通過註解注入了一個userService,使用userService對資料庫進行操作。
問題就在於,因為我的userService中使用的userDao並不是一個具體的實現類,而是一個interface,因為我定義的userDao繼承了JpaSpecificationExecutor和JpaRepository 介面,原先在UserService中注入UserDao使用的是@Autowire註解,結果啟動tomcat的過程中報錯,說無法初始化userDao的bean,這個問題困擾了我大半天,各種網上找解決方案,問人,都沒結果。後來不知道為什麼,稀裡糊塗的就把UserService中UserDao上的@Autowire這個註解換成了@Resource註解,問題居然就這麼解決了,使用了一下,發現沒有問題。
這是我自己定義的Realm的程式碼:
這是我的UserService的程式碼:package com.sg.shirotest; import com.sg.model.UserEntity; import com.sg.service.UserService; import org.apache.shiro.authc.*; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.springframework.beans.factory.annotation.Autowired; import java.util.HashSet; import java.util.Set; public class MyShiroRealm extends AuthorizingRealm { @Autowired private UserService userService; public void setUserService(UserService userService) { this.userService = userService; } /** * 授權 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { Set<String> roleNames = new HashSet<String>(); Set<String> permissions = new HashSet<String>(); roleNames.add("admin");//新增角色 permissions.add("admin.html"); //新增許可權 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roleNames); info.setStringPermissions(permissions); return info; } /** * 登入驗證 */ @Override protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken authcToken) throws AuthenticationException { UsernamePasswordToken token = (UsernamePasswordToken) authcToken; UserEntity user = this.userService.getUserByAccount(token.getUsername()); if(user != null){ return new SimpleAuthenticationInfo(user.getAccount(),user.getPassword(),getName()); }else{ throw new AuthenticationException(); } } }
package com.sg.service;
import com.sg.model.Role;
import com.sg.model.UserEntity;
import com.sg.repository.UserDao;
import com.sg.web.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springside.modules.persistence.DynamicSpecifications;
import org.springside.modules.persistence.SearchFilter;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Created by sg on 2016/7/19.
*/
@Component
@Transactional
public class UserService {
@Resource
private UserDao userDao;
public void saveUser(UserEntity user){
this.userDao.save(user);
}
public void deleteUser(UserEntity user){
this.userDao.delete(user);
}
public UserEntity getUserById(Long id){
return this.userDao.findOne(id);
}
public List<UserEntity> getAllUser(){
return this.userDao.findAll();
}
public UserEntity getUserByAccount(String account){
return this.userDao.getUserByAccount(account);
}
public Page<UserEntity> getPageUserByParams(int pageNumber, int pageSize, String sortName, String sortType, Map<String, String> params) {
List<SearchFilter> filters = new ArrayList<SearchFilter>();
if (params.get("account") != null) {
filters.add(new SearchFilter("account", SearchFilter.Operator.LIKE, params.get("account")));
}
filters.add(new SearchFilter("state", SearchFilter.Operator.EQ,1));
Specification<UserEntity> spec = DynamicSpecifications.bySearchFilter(filters,
UserEntity.class);
// 分頁排序處理
Sort sort = new Sort(StringUtils.getSortType(sortType), sortName);
PageRequest pageRequest = new PageRequest(pageNumber - 1, pageSize, sort);
return this.userDao.findAll(spec, pageRequest);
}
}
這是我的UserDao的程式碼:
package com.sg.repository;
import com.sg.model.UserEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
/**
* Created by sg on 2016/7/19.
*/
public interface UserDao extends JpaSpecificationExecutor<UserEntity>,JpaRepository<UserEntity,Long> {
@Query("select user from UserEntity user where user.account = ?1 and user.state = 1")
UserEntity getUserByAccount(String account);
}
去網上找了一下為什麼,看到別人寫的@Autowire與@Resource的區別,還是不怎麼明白這個問題解決的根本原因。
網上說:
@Autowired預設按型別裝配(這個註解是屬於spring的),預設情況下必須要求依賴物件必須存在,如果要允許null值,可以設定它的required屬性為false如:@Autowired(required=false) @Resource 是JDK1.6支援的註解,預設按照名稱進行裝配,名稱可以通過name屬性進行指定,如果沒有指定name屬性,當註解寫在欄位上時,預設取欄位名,按照名稱查詢,如果註解寫在setter方法上預設取屬性名進行裝配。當找不到與名稱匹配的bean時才按照型別進行裝配。但是需要注意的是,如果name屬性一旦指定,就只會按照名稱進行裝配。 可能是因為我定義的UserDao是介面型別的,沒有辦法例項化,但是再一想也不對,在Controller中注入的Service中的dao都是用@Autowire進行注入的,那些就沒問題。目前為止還是不明白,先知道怎麼解決吧,等明白了,想起來了再來補上。