1. 程式人生 > >Shiro Realm @Autowired 注入失敗的問題

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的程式碼:

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();
        }
    }

}
這是我的UserService的程式碼:
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進行注入的,那些就沒問題。目前為止還是不明白,先知道怎麼解決吧,等明白了,想起來了再來補上。