2015年12月29日 星期二

@Component 和 JSR330 的 Annotation (Spring3.x 十三)

參考文件

上一篇的xml還是要宣告,現在可以將它完全刪了
@Component("bo") // Book.java
@Component("ca") // Cartoon.java
@Component("co") // Comic.java

※在三支vo的class上面增加如上的annotation
這時xml只要這兩行就可以了
<context:annotation-config />
<context:component-scan base-package="\" />



轉換個場景,一般在開發時都會有controller-->Service-->ServiceImpl-->DAO可以這樣定義

※XML設定

BookAction.java

public class BookAction {
    private IBookService service;
    
    public void setService(BookServiceImpl service) {
        this.service = service;
    }
    
    public void go() {
        service.get();
    }
}



IBookService.java

public interface IBookService {
    public void get();
}



BookServiceImpl.java

public class BookServiceImpl implements IBookService {
    private BookDAOImpl dao;
    
    public void setDao(BookDAOImpl dao) {
        this.dao = dao;
    }
    
    public void get() {
        dao.getBook();
    }
}



BookDAOImpl.java

public class BookDAOImpl {
    public void getBook() {
        System.out.println("資料庫操作");
    }
}



applicationContext.xml

<bean id="bookAction" class="controller.BookAction" p:service-ref="bookServiceImpl" />
<bean id="bookServiceImpl" class="serviceImpl.BookServiceImpl" p:dao-ref="bookDAOImpl" />
<bean id="bookDAOImpl" class="dao.BookDAOImpl" />



測試類

ApplicationContext ctx2 = new ClassPathXmlApplicationContext("applicationContext.xml");
    
BookAction c = (BookAction) ctx2.getBean("bookAction");
c.go();
    
((ClassPathXmlApplicationContext) ctx2).close();

結果:
資料庫操作




※Annotation設定

BookAction.java

package controller;
    
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import service.IBookService;
import serviceImpl.BookServiceImpl;
    
@Controller
public class BookAction {
    // @Resource
    @Autowired
    private IBookService service;
    
    public void setService(BookServiceImpl service) {
        this.service = service;
    }
    
    public void go() {
        service.get();
    }
}



BookServiceImpl.java

package serviceImpl;
    
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import dao.BookDAOImpl;
import service.IBookService;
    
@Service
public class BookServiceImpl implements IBookService {
    // @Autowired
    @Resource
    private BookDAOImpl dao;
    
    public void setDao(BookDAOImpl dao) {
        this.dao = dao;
    }
    
    public void get() {
        dao.getBook();
    }
}



BookDAOImpl.java

@Repository
public class BookDAOImpl {
    public void getBook() {
        System.out.println("資料庫操作");
    }
}



applicationContext.xml

<context:annotation-config />
<context:component-scan base-package="\" />



測試類

ApplicationContext ctx1 = new AnnotationConfigApplicationContext("applicationContext.xml");
    
System.out.println(ctx1.getBeanDefinitionCount());
for (String s : ctx1.getBeanDefinitionNames()) {
    System.out.println(s);
}
    
((AnnotationConfigApplicationContext) ctx1).close();
System.out.println("----------------------------------------");
ApplicationContext ctx2 = new ClassPathXmlApplicationContext("applicationContext.xml");
    
System.out.println(ctx2.getBeanDefinitionCount());
for (String s : ctx2.getBeanDefinitionNames()) {
    System.out.println(s);
}
    
IBookService service1 = ctx2.getBean("bookServiceImpl", IBookService.class);
BookServiceImpl service2 = (BookServiceImpl) ctx2.getBean("bookServiceImpl");
service1.get();
service2.get();
    
BookAction c = (BookAction) ctx2.getBean("bookAction");
c.go();
    
((ClassPathXmlApplicationContext) ctx2).close();
System.out.println("----------------------------------------");
    
ApplicationContext ctx3 = new AnnotationConfigApplicationContext(BookAction.class, BookServiceImpl.class,
        BookDAOImpl.class);
    
System.out.println(ctx3.getBeanDefinitionCount());
for (String s : ctx3.getBeanDefinitionNames()) {
    System.out.println(s);
}
    
IBookService service3 = ctx3.getBean("bookServiceImpl", BookServiceImpl.class);
BookServiceImpl service4 = (BookServiceImpl) ctx3.getBean("bookServiceImpl");
service3.get();
service4.get();
    
BookAction controller = (BookAction) ctx3.getBean("bookAction");
controller.go();
    
((AnnotationConfigApplicationContext) ctx3).close();

※結果:
5
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor
-------------------------------------------------------------------------
8
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
bookAction
bookDAOImpl
bookServiceImpl
org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor
資料庫操作
資料庫操作
資料庫操作
-------------------------------------------------------------------------
8
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
bookAction
bookServiceImpl
bookDAOImpl
org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor
資料庫操作
資料庫操作
資料庫操作

※service.java什麼註解都不用,和xml設定的一樣,註了也沒什麼效果

※@Controller、@Service、@Repository這三個annotation裡面都包括@Component,所以也可以用@Component代替,經測試過這四個annotation可以隨便使用,不過最好是按照它的名稱來使用會比較直覺
@Controller:就放在controller上
@Service:就放在service上
@Repository:就放在DAO上
而預設的id名稱就是class名稱,然後第一個字改小寫,所以上面的controller也等於@Controller("bookAction"),測試類在拿來用即可

※上面還有@Resource和@Autowired,有這兩個其中之一,setter可以不寫,會自動塞值
如果沒有這兩個annotation,service和dao會是null,所以在「.」就會NullPointException,不想用annotation的話只能new了-->private BookDAOImpl dao = new BookDAOImpl();

※getBeanDefinitionCount方法可以取得所有的bean數目,預設有5筆; getBeanDefinitionNames方法可以取得所有的bean名稱

※測試類一共有三種取bean的方式,ctx1是不行的,因為bean數目是預設的5筆

※這次的專案內容路徑



※@Scope

和之前的xml設定一樣,可以控制要不要同一個實體

BookAction.java

@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Controller
public class BookAction {}



applicationContext.xml

ApplicationContext ctx2 = new ClassPathXmlApplicationContext("applicationContext.xml");
    
BookAction s1 = (BookAction) ctx2.getBean("bookAction");
System.out.println(s1);
    
BookAction s2 = (BookAction) ctx2.getBean("bookAction");
System.out.println(s2);
    
((ClassPathXmlApplicationContext) ctx2).close();




※JSR330 的 Annotation

參考資料
Spring                      javax.inject.*
@Autowired                  @Inject
@Component                  @Named
@Scope("singleton")         @Singleton
@Qualifier                  @Named
@Value                      無
@Required                   無
@Lazy                       無

※連結往上一點,就會看到有maven的jar可以複製,我覺得這張表已經很清楚了,我沒有全試,不過run起來還蠻順的,要注意@Named可以用在兩個地方



※自動裝配 Map、List


package xxx;
    
public interface IspeakService {
    void speak();
}
    
    
    
package xxx;
    
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;
    
@ComponentScan("xxx")
@Component
public class Bird implements IspeakService {
    public void speak() {
        System.out.println("吱吱吱");
    }
}
    
    
    
package xxx;
    
import org.springframework.stereotype.Component;
    
@Component
public class Lion implements IspeakService {
    public void speak() {
        System.out.println("吼吼吼");
    }
}

※一個介面多個實作


package xxx;
    
import xxx.Bird;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
    
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = Bird.class)
public class TestSomething {
    @Resource
    public Map<String, IspeakService> mapService;
    
    @Resource
    public List<IspeakService> listService;
    
    @Test
    public void testXxx() {
        System.out.println(mapService);
        listService.forEach(x -> System.out.println(x.getClass()));
    }
}

※直接使用 @Autowired 或 @Resource 就可以直接抓到了

※Map 的 key 值是 @Component 的小寫開頭類名

※可以利用這個特性做多型

沒有留言:

張貼留言