spring 3.0
TRANSCRIPT
Spring Core
Scott
• Inversion Of Control (IoC)• Aspect-Oriented Programming (AOP)• Testing
Inversion Of Control (IoC)
A
B C
A
B C
IoC
如何設定bean?
package com.gorilla.netstream.user.service.impl
public class AccountServiceImpl implements AccountService {public Account loadAccount(Long accountId) {
Account account = dao.findAccount(accountId);return account;
}}
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:context="http://www.springframework.org/schema/context"xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-
context-3.2.xsd">
<bean id="accountService" class="com.gorilla.netstream.user.service.impl.AccountServiceImpl" ></bean>
</beans>
Naming Rule
Ex: loginController, accountService, userDao
Dependency Injection
package com.gorilla.netstream.user.service.impl
public class AccountServiceImpl implements AccountService {private AccountDao dao;public Account loadAccount(Long accountId) {
Account account = dao.findAccount(accountId);return account;
}}
package com.gorilla.netstream.user.dao.implpublic class AccountDaoImpl implements AccountDao {
public Account findAccount(Long accountId) {…return account;
}}
Dependency Injection: Constructor-Based
package com.gorilla.netstream.user.service.impl
public class AccountServiceImpl implements AccountService {private AccountDao dao;
public AccountServiceImpl(AccountDao dao) {this.dao = dao;
}
public Account loadAccount(Long accountId) {Account account = dao.findAccount(accountId);return account;
}}
<beans …>
<bean id="accountService" class="com.gorilla.netstream.user.service.impl.AccountServiceImpl" ><constructor-arg ref="accountDao" />
</bean>
<bean id="accountDao" class="com.gorilla.netstream.user.dao.impl.AccountDaoImpl" />
</beans>
Dependency Injection: Setter-Based
package com.gorilla.netstream.user.service.impl
public class AccountServiceImpl implements AccountService {private AccountDao dao;
public void setDao(AccountDao dao) {this.dao = dao;
}
public Account loadAccount(Long accountId) {Account account = dao.findAccount(accountId);return account;
}}
<beans …>
<bean id="accountService" class="com.gorilla.netstream.user.service.impl.AccountServiceImpl" ><property name="dao" ref= “accountDao" /><!--<property name="dao" >
<ref bean="accountDao" /></property>-->
</bean>
<bean id="accountDao" class="com.gorilla.netstream.user.dao.impl.AccountDaoImpl" />
</beans>
Bean Scopes – Singleton
<bean id="accountService1" class="…" ><constructor-arg ref="accountDao" />
</bean>
<bean id="accountService2" class="…" ><constructor-arg ref="accountDao" />
</bean>
<bean id="accountService3" class="…" ><constructor-arg ref="accountDao" />
</bean>
<bean id="accountDao" class="…" />
1.
Bean Scopes – Prototype
<bean id="accountService1" class="…" ><constructor-arg ref="accountDao" />
</bean>
<bean id="accountService2" class="…" ><constructor-arg ref="accountDao" />
</bean>
<bean id="accountService3" class="…" ><constructor-arg ref="accountDao" />
</bean>
<bean id="accountDao" class="…" />
1.
2.
3.
Bean Scopes
• Singleton: 每一個Spring Container會共用同一個Bean Instance。(default)
• Prototype: 每一次Request都會建立一個新的Instance來服務。
• Request: 每一次HTTP Request都共用同一個Bean Instance。
• Session: 每一個HTTP Request都共用同一個Bean Instance。
• Global Session: 每一個Global HTTP Request都共用同一個Bean Instance。(Portlet only)
Annotation-based
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context=http://www.springframework.org/schema/contextxsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config />
</beans>
@Required
package com.gorilla.netstream.user.service.impl
public class AccountServiceImpl implements AccountService {private AccountDao dao;
@Requiredpublic void setDao(AccountDao dao) {
this.dao = dao;}
public Account loadAccount(Long accountId) {Account account = dao.findAccount(accountId);return account;
}}
@Autowired
package com.gorilla.netstream.user.service.impl
public class AccountServiceImpl implements AccountService {@Autowiredprivate AccountDao dao;
@Autowiredpublic void setDao(AccountDao dao) {
this.dao = dao;}
@Autowiredpublic AccountServiceImpl(AccountDao dao) {
this.dao = dao;}
}
擇一使用
@Qualifierpackage com.gorilla.netstream.user.service.impl
public class AccountServiceImpl implements AccountService {
@Autowired@Qualifier("accountDao")private AccountDao accountDao;
}
支援JSR-250• @Resource• @PostConstruct• @PreDestory
支援JSR-330• @Inject• @Qualifier• @Named• @Provider
@Autowired v.s. @Resource
Classpath scanning
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context=http://www.springframework.org/schema/contextxsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.gorilla.netstream.*.service" />
</beans>
• @Component• @Repository• @Service• @Controller
Aspect-Oriented Programming (AOP)
横切的關注點
CourseService
StudentService
MiscService
Security
Log
Transactio
n
Oth
er
AOP術語
• 切面(Aspect):一個關注點的模組化,這個關注點可能會橫切多個物件。
• 連接點(Joinpoint):在程序執行過程中某個特定的點,比如某方法調用的時候或者處理異常的時候。
• 通知(Advice):在Aspect的某個特定的連接點上執行的動作。• 切入點(Pointcut):用於指定某Aspect在某Joinpoint中織入到應用程序之上。
• 引入(Introduction):用來給一個型別宣告額外的方法或屬性。• 目標物件(Target Object):一個Advice被應用的目標物件。• AOP代理(AOP Proxy):AOP框架創建的物件,用來實作切面契約(例如通知方法執行等等)。
• 織入(Weaving):把Aspect應用到Target上的過程。
<beans …><aop:aspectj-autoproxy expose-proxy="true" /></beans>
@Aspect@Componentpublic class ExcuteLogAspect {
public final static Logger log = Logger.getLogger("System");
@Pointcut("execution(* com.gorilla.netstream.*.service.impl.*.*(..))")public void inService() {}
@Pointcut("execution(* com.gorilla.netstream.*.dao.impl.*.*(..))")public void inDao() {}
@Before("inService() || inDao()")public void before(JoinPoint jp) {
log.info("Calling " + jp.getSignature().getDeclaringType().getSimpleName() + "." + jp.getSignature().getName() + ".");
}
@Around("inService() || inDao()")public Object around(ProceedingJoinPoint pjp) throws Throwable {
long start = System.currentTimeMillis();Object output = pjp.proceed();long end = System.currentTimeMillis();long elapsedTime = end - start;log.info(pjp.getSignature().toShortString() + ", execution time: " + elapsedTime + " milliseconds.");return output;
}
@AfterThrowing(pointcut="inService() || inDao()", throwing="ex")public void afterThrowing(JoinPoint jp,Throwable ex) {
log.info(jp.getSignature().toShortString() + " throw exception.", ex);}
}
@Aspect@Componentpublic class ExcuteLogAspect {
…}
@Pointcut("execution(* com.gorilla.netstream.*.service.impl.*.*(..))")public void inService() {}
@Before("inService() || inDao()")public void before(JoinPoint jp) {
log.info("Calling " + jp.getSignature().getDeclaringType().getSimpleName() + "." + jp.getSignature().getName() + ".");}
@Around("inService() || inDao()")public void before(JoinPoint jp) {
long start = System.currentTimeMillis();Object output = pjp.proceed();long end = System.currentTimeMillis();long elapsedTime = end - start;log.info(pjp.getSignature().toShortString() + ", execution time: " + elapsedTime + " milliseconds.");return output;
}
• @Before• @AfterReturning• @AfterThrowing• @Around• @After
Testing
package test.gorilla.netstream.user.service
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(locations={"classpath:/conf/spring/application-*.xml"})public class AccountServiceTest {
@Resourceprivate AccountService accountService;
@Testpublic void test() {
…}
}
package test.gorilla.netstream.user.service
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(locations={"classpath:/conf/spring/application-*.xml"})public class AccountServiceTest {…}
package test.gorilla.netstream.user.service
@RunWith(SpringJUnit4ClassRunner.class)// classpath:/test/gorilla/netstream/user/service/AccountServiceTest-context.xml@ContextConfigurationpublic class AccountServiceTest {…}
package test.gorilla.netstream.user.service
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes={AppConfig.class, TestConfig.class})public class AccountServiceTest {…}
Testing Annotation
http://docs.spring.io/spring/docs/3.2.10.RELEASE/spring-framework-reference/htmlsingle/#integration-testing-annotations
Q & A