Spring中IoC - 两种ApplicationContext加载Bean的配置
说明:Spring IoC其实就是在Service的实现中定义了一些以来的策略类,这些策略类不是通过 初始化、Setter、工厂方法来确定的。而是通过一个叫做上下文的(ApplicationContext)组建来加载进来的。这里介绍两种Context组建的构件过程
前提条件:在Gradle工程的build.gradle文件中引入对Spring framework 的支持
repositories { mavenCentral() } dependencies { compile group: 'org.springframework',name: 'spring-context', version: '4.1.5.RELEASE' compile group: 'org.springframework',name: 'spring-core', version: '4.1.5.RELEASE' testCompile group: 'junit', name: 'junit', version: '4.11' }
第一种方式:通过ClassPathXmlApplicationContext加载xml配置文件
这里使用greenmail做测试邮件的例子来介绍:
1. 依赖管理
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.ygshen.mvnbook.account</groupId> <artifactId>account-service</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <!-- https://mvnrepository.com/artifact/org.springframework/spring-context --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.3.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-beans --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>4.3.3.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-core --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>4.3.3.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-context-support --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>4.3.3.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/javax.mail/mail --> <dependency> <groupId>javax.mail</groupId> <artifactId>mail</artifactId> <version>1.4.1</version> </dependency> <!-- https://mvnrepository.com/artifact/junit/junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.7</version> <scope>test</scope> </dependency> <!-- https://mvnrepository.com/artifact/com.icegreen/greenmail --> <dependency> <groupId>com.icegreen</groupId> <artifactId>greenmail</artifactId> <version>1.5.2</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.5</source> <target>1.5</target> </configuration> </plugin> </plugins> </build> </project>
2. 接口定义
public interface emailService { public void sendMail(String to, String subject,String htmlText) throws MessagingException; }
3. 接口实现
public class emailServiceImp implements emailService{ //这里有两个IOC的变量,后面将通过bean+property的方式进行依赖管理 private JavaMailSender javaMailSender; private String systemAccount; // Get和Set时必须的 public JavaMailSender getJavaMailSender() { return javaMailSender; } public void setJavaMailSender(JavaMailSender javaMailSender) { this.javaMailSender = javaMailSender; } public String getSystemAccount() { return systemAccount; } public void setSystemAccount(String systemAccount) { this.systemAccount = systemAccount; } //发送邮件主题函数,javamailsender是 spring的邮件类。这个mail sender就是发送邮件的smtp服务器。 // 如Gmail等,这里将在测试用例中使用greenemail代替他门 public void sendMail(String to, String subject, String htmlText) throws MessagingException { MimeMessage message = javaMailSender.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(message); helper.setFrom(systemAccount); helper.setTo(to); helper.setSubject(subject); helper.setText(htmlText); javaMailSender.send(message); } }
4. Bean文件定义:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--定义自动获取property配置--> <bean id="propertyConfigure" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="classpath:service.properties"></property> </bean>
<!--定义java mail sender bean 对象,这个bean后边将作为依赖注入到service中--> <bean id="javaMailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl"> <property name="protocol" value="${email.protocol}"></property> <property name="port" value="${email.port}"></property> <property name="host" value="${email.host}"></property> <property name="username" value="${email.username}"></property> <property name="password" value="${email.password}"></property> <property name="javaMailProperties"> <props> <prop key="mail.${email.protocol}.auth">${email.auth}</prop> </props> </property> </bean> <!--真正负责发送邮件的类定义bean--> <bean id="accountService" class="com.ygshen.mvnbook.account.email.emailServiceImp"> <property name="javaMailSender" ref="javaMailSender"></property> <property name="systemAccount" value="${email.systemAccount}"></property> </bean> </beans>
5. Property 文件
email.protocol=smtps
email.host=smtp.gmail.com
email.port=465
email.username=shenyuangong@gmail.com
email.password=111111
email.auth=true
email.systemAccount=ygshen@163.com
初始化javamailsender的配置文件。 main/Resources目录下。注意这个配置文件将在test/resource中 重新定义目的是模拟测试
6. 测试代码:
package com.ygshen.mvnbook.account; import com.icegreen.greenmail.util.GreenMail; import com.icegreen.greenmail.util.ServerSetup; import com.ygshen.mvnbook.account.email.emailService; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import javax.mail.Message; import javax.mail.MessagingException; /** * Created by ygshen on 16/10/31. */ //这里需要注意junit的测试文件必须以Test结尾 否则 mvn clean test 的时候将没有办法获取到测试用例 public class emailServiceTest { //这里初始化一个本地的greenmail作为测试邮箱服务器 private GreenMail mail; @Before public void startMailBox(){ mail = new GreenMail(new ServerSetup(12000,null,"smtp")); mail.setUser("shenyuangong@gmail.com", "123456"); mail.start(); } @Test public void sendMail() throws MessagingException { ApplicationContext context = new ClassPathXmlApplicationContext("account-service.xml"); // 这里将初始化发送邮件的service,而service所依赖的javamailsender初始化所配置的邮箱服务器和start中 定义的port、protocol也是一样的。 在测试test/resources中定义。这里greenmail起到模拟gmail服务器的能力 emailService service = (emailService)context.getBean("accountService"); service.sendMail("test2@163.com","Test Subject","<h1>test</h1>"); mail.waitForIncomingEmail(2000,1); Message[] msgs = mail.getReceivedMessages(); Assert.assertEquals(1,msgs.length); } @After public void closeMail(){ mail.stop(); } }
7. 测试用的Properties文件
email.protocol=smtp
email.host=localhost
email.port=12000
# 注意这里的邮箱登陆的帐号要和Greenmail中 setUser使用的相同才行。
email.username=shenyuangong@gmail.com
email.password=123456
email.auth=true
email.systemAccount=ygshen@163.com
第二种方式:AnnotationConfigApplicationContext类加载JavaClass File的配置文件
配置文件JavaClass如下:
@Configuration:表示这是一个配置文件
@Bean: 表示这是一个Bean(名字为方法名),将来他要用来与Service中的@Autowired属性配对,注意配对的时候是根据返回类型来对应的,也就是说所有的Service中但凡有@Autowired的属性,他们都是从这个配置文件中拿到的。
@Configuration public class ApplicationContextConfiguration { @Bean public AccountRepoisitory accountRepoisitory() { return new AccountRepositoryImp(); } @Bean public TransactionService transactionService() { return new TransactionServiceImp(); } @Bean public TransferService transferService() { return new TransferServiceImp(); } }
再来看一下使用@AutoWired的Service类。这个AutoWired将与上面配置文件中的@Bean结成一对儿
public class TransactionServiceImp implements TransactionService { @Autowired public AccountRepoisitory accountRepoisitory; @Override public void NewTransaction(String accountId1, String accountId2, double money) { Account account1=accountRepoisitory.GetAccountByAccountId(accountId1); Account account2=accountRepoisitory.GetAccountByAccountId(accountId2); Transaction transaction=new Transaction(){ }; transaction.fromAccount=account1; transaction.toAccount=account2; transaction.moneyTransfered=money; transaction.transactionDate= Calendar.getInstance().getTime(); BankFactory.Transactions.add(transaction); } }
最后来看Main函数是如何将配置文件与Service文件结合在一起的。 很简单
ApplicationContext context= new AnnotationConfigApplicationContext( com.ctrip.configuration.ApplicationContextConfiguration.class );
// 接下来我们就可以使用任何Service中定义的方法了
AccountRepoisitory accountRepoisitory=context.getBean("accountRepoisitory",
AccountRepositoryImp.class);
TransactionService transactionService=context.getBean("transactionService",
TransactionServiceImp.class);
TransferService transferService=context.getBean("transferService",
TransferServiceImp.class
);
transferService.Transfer("1","2",234);