一篇文章學會spring boot(包括jms和hessian的集成)
之前在學習spring cloud微服務的時候,由於spring cloud的基礎是spring boot,因此曾簡單地了解過spring boot,但也隻是簡單的了解過而已。
而現在,需要把struts2項目改為spring boot,一開始時以為是整個項目重構,不僅限於struts2部分,因此就相對更係統、更細致的學了一下spring boot。
整個過程由易到難,大概分成了這麼些模塊:
一、創建簡單的spring boot web項目
很多時候學一個新的東西,都需要從最簡單的地方開始,然後讓自己看到成功後的效果,這樣才能更有信心繼續下去,至於這第一步,我在寫spring cloud相關學習記錄的時候,第一篇就是spring boot,因此便不需要再寫一遍,那一篇博客是:
springcloud微服務一:spring boot基礎項目搭建及問題處理
二、配置文件加載類
雖然說spring boot原則上是建議去掉xml配置文件,但是對於一個已經成型並上線運行著的項目而言,不論是代碼還是配置都是非常龐大而且複雜的。
這些配置文件不隻是spring的、struts2的,還有spring和mq集成的,還有spring和hessian集成的等等。
僅涉及到spring和struts2的配置文件比較好改,而spring和mq以及hessian集成的就稍微有些麻煩。
因此在一開始我心中便有了一個設想,就是mq集成和hessian集成的部分先還是以配置文件的方式不變,等簡單易改的部分搞定後再說,於是便需要知道在沒有了web.xml文件的spring boot項目中,我需要如何引入加載這些暫時不能去掉的xml文件。
經了解之後發現其實還是很簡單的,隻需要自己再寫一個空的java類,然後使用兩個注解就好:
@Configuration
@ImportResource(value = "classpath:spring.xml")
public class ConfigClass {
}
@Configuration是向spring聲明這是個配置類,@ImportResource則是指明需要引入的配置文件路徑。
三、使用注解給屬性賦值
在過去的項目中,有一些數據存放在properties文件中,然後在spring的xml文件中引用,從而給特定的對象的屬性賦值。
而如果整個項目改成spring boot,就需要盡可能去掉能去掉的xml配置文件,就沒有了這種注入賦值,所以還需要知道怎樣在spring boot中達到xml文件配置一樣的賦值效果。
經了解後發現也是比較簡單地,隻需要在對應的屬性上使用@Value注解:
public class User {
@Value("${tuser.name}")
private String name;
@Value("${tuser.age}")
}
當然了,這種寫法的前提是在properties文件中有相應的屬性配置,例如:
tuser.name=testtttttt
tuser.age=123
並且spring boot項目啟動後能夠加載到這個properties文件,spring boot默認會加載resources目錄下的application.properties文件,如果我們這些配置不在這個文件中,還需要進行其他的配置,例如在application.properties文件中使用spring.profiles.active進行指定。
四、使用注解給對象賦值:
雖然說在java中有一切皆對象的說法,屬性和屬性所屬對象都統稱對象,但是這裏為了區分,我隻能在上邊更精確的說到屬性。
而上邊那種賦值方式有個很明顯的缺陷,就是每個屬性都需要使用@Value注解,如果這個類恰好很大,有幾十個屬性,那麼這種賦值將是一個很讓人煩躁的工作。
而spring boot中也正好提供了一個更加方便的方式,隻需要一個注解,就可以引用配置文件中的內容給整個對象賦值。
例如配置文件中有如下內容:
mytest:
user:
name: test
age: 22
phone: 13533559797
上邊這種寫法是yaml文件的寫法,也就是在spring boot中默認識別properties類型的配置文件和yaml的配置文件。
上邊的寫法實際上等同於properties文件中如下的寫法:
mytest.user.name=test
mytest.user.age=22
mytest.user.phone=13533559797
而我們要把這樣一些配置直接賦值給特定對象的方式,就是使用@ConfigurationProperties注解:
@ConfigurationProperties(prefix = "mytest.user")
public class User {
// @Value("${test.user.name}")
private String name;
// @Value("${age}")
private int age;
// @Value("${phone}")
private String phone;
}
類上邊的那個注解等同於下邊被注釋掉的三個注解,當然了,不論哪種方式,實現的前提都是這個user類能夠被spring 掃描到,也就是說能夠被spring所管理。
五、filter過濾器
在原本的spring web項目中,web.xml文件是必不可少的,啟動tomcat後就會來加載這個文件。
通常我們都會在這個文件中配置一些servlet以及過濾器,例如字符集過濾器,而spring boot不再使用web.xml,就需要我們能夠用其他方式解決原本web.xml中的過濾器的問題。
這裏寫一個過濾器也很簡單,要實現javax.servlet.Filter接口,並借助幾個注解,隻不過這個功能應該是java自己的,而不是spring boot新提供的:
/**
*@auth tuzongxun
*/
@WebFilter(filterName = "myFilter", urlPatterns = "/*")
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("進入filter");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
chain.doFilter(request, response);
}
@Override
public void destroy() {
System.out.println("走出filter");
}
}
六、listener監聽器
說到了過濾器,接下來自然要說的就是監聽器,在java web項目中,過濾器和監聽器都用的很多,也都常常在web.xml文件中有相應的配置。
在spring boot中寫一個監聽器就更加簡單,比如就僅僅是下邊的幾行代碼就夠了:
@WebListener
public class MyListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("contextlistener init");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("contextlistener destroy");
}
}
同樣的,上邊的類所實現的接口以及相應的注解也都不是spring boot的,而是javax.servlet的。
上邊例子中我們寫的是一個contextListener,同樣的也可以寫一個requestListener以及其他的listener,例如:
@WebListener
public class MyListener1 implements ServletRequestListener {
@Override
public void requestDestroyed(ServletRequestEvent sre) {
System.out.println("requestlistener destroy");
}
@Override
public void requestInitialized(ServletRequestEvent sre) {
System.out.println("requestlistener init");
}
}
七、ERROR錯誤頁麵
在web.xml中除了配置了filter和listener外,比較常見的就還有配置error錯誤頁麵,我們項目中也同樣這麼做了,因此在拋棄web.xml的時候,也必然要考慮error頁麵的問題,那麼在spring boot中也同樣是非常的簡單,比如寫這樣一個類:
@Component
public class Test {
@Bean
public EmbeddedServletContainerCustomizer containerCustomizer() {
return new EmbeddedServletContainerCustomizer() {
@Override
public void customize(ConfigurableEmbeddedServletContainer container) {
ErrorPage error404Page = new ErrorPage(HttpStatus.NOT_FOUND, "/404.html");
ErrorPage error500Page = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/500.html");
container.addErrorPages(error404Page, error500Page);
}
};
}
}
需要注意的是,我這種寫法是jdk1.6可用的,還有一種寫法需要jdk1.7以上版本才行,這裏就不舉例了。
並且我這裏是寫了一個新的類,我們也可以直接把具體的方法寫到啟動類那裏,效果是一樣的,隻要都能被spring 掃描到。
八、定時任務
原本項目中使用了quartz定時任務,使用了大量的xml配置文件,這裏就使用schedule替代。
不過,這一條雖然列在了這裏,但是實際上我覺得可以不用列出來,因為這裏使用schedule代替quartz,實際上也是spring原本就有的,並不是有了spring boot之後才出現,具體的我也曾寫過相應的博客,例如:
spring schedule定時任務(一):注解的方式
隻不過,在spring boot中更加的簡單,不需要我們再做任何的動作,隻需要這個簡單的類和注解就ok了:
@Component
@EnableScheduling
public class MySchedule {
@Scheduled(cron = "*/2 * * * * ?")
public void sTest() {
System.out.println(Calendar.getInstance().getTime());
}
}
九、返回頁麵
返回頁麵,在spring boot中叫引用模板,需要特定的依賴,例如:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
當然了,這隻是其中一種。
引入了相應的依賴後,我們在spring boot項目的resources目錄下的templates目錄下建立具體的html頁麵,然後具體的controller中隻需要返回相應的html的文件名,即能成功返回頁麵。
例如templates下有index.html文件,在controller中就可以寫成這樣:
@RequestMapping("/index")
public String index(ModelMap map) {
map.put("name", "testfsdfdsfdsfsdf");
return "index";
}
不過這裏我覺得應該也可以使用modelandview,但並沒有嚐試,不知是否可行,而且即便可行,在性能上如何也還未曾測試。
十、spring boot 集成activemq,即jms
前文中我有說到我們原本的項目中使用了spring 整合activemq,那麼改為spring boot後不可能就把activemq扔掉,還需要找到可行的集成方案,可喜的是,spring boot中有jms專門集成activemq。
要實現這種集成,我們首先還需要導入jms相應的依賴,創建項目的時候選擇jms,會在pom.xml文件中生成如下內容:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
使用activemq發送消息需要有消息隊列,因此接下來就需要我們生成一個消息隊列的配置類,用來指定queue:
@Configuration
@EnableJms
public class ActiveMQConfig {
@Bean // 配置一個消息隊列
public Queue queue() {
return new ActiveMQQueue("sample.queue");
}
}
有了隊列以後,然後就是發送消息:
@Service
public class MQProduceService {
@Autowired
private JmsMessagingTemplate jmsMessagingTemplate;
@Autowired
private Queue queue;
public void send(String msg) {// 向指定隊列中發送消息
this.jmsMessagingTemplate.convertAndSend(this.queue, msg);
}
}
就這樣簡單兩步,我們的activemq消息服務器就算是寫好了,如果再其他地方調用這個service中對應的方法,就可以實現消息的發送。
有了發送端,還需要有接受端,或者說消費端。也是需要先配置隊列,因為我這裏都寫在一個項目中,所以就公用同一個配置就好,具體的消費端代碼如下:
@Service
public class MQConsumerService {
private String text;
@JmsListener(destination = "sample.queue") // 監聽指定消息隊列
public void receiveQueue(String text) {
this.text = text;
System.out.println(text);
}
public String receive() {
return text;
}
}
不論是發送端還是消費端,代碼都很簡單,為了更直觀的看到結果,我編寫了一個controller來調用相應的服務實現發送和接受,代碼如下:
@RestController
public class MQController {
@Autowired
private MQProduceService produceService;
@Autowired
private MQConsumerService consumerService;
@RequestMapping("/send")
public String send() {
produceService.send("this is an activemq message");
return "send";
}
@RequestMapping("/receive")
public String receive() {
String str = consumerService.receive();
return str;
}
}
這個代碼非常的常規,也就不做多的解釋了。
十一、spring boot中使用hessian
mq分為發送端和消費端,而hessian作為一種webservice,也是一樣具有服務端和消費端,不過與mq不同的是,hessian需要在web.xml進行一定的配置。
與之前hessian的實現方式一樣的是,服務端需要有相應的接口類和實現類,例如:
public interface HelloWorld {
public String hello();
public Map<String, String> helloMap();
}
@Service("helloWorld")
public class HelloWorldImpl implements HelloWorld {
private static final long serialVersionUID = 1L;
@Override
public String hello() {
return "hello hessian";
}
@Override
public Map<String, String> helloMap() {
Map<String, String> map = new HashMap<String, String>();
map.put("message", "hello word!!!!!");
return map;
}
}
而不同的是,之前使用web.xml時在web.xml中進行了配置,而在這裏則是使用了一個類來暴露接口:
@Component
public class HService {
@Autowired
private HelloWorld helloWorld;
@Bean(name = "/springBootDemo/HelloService")
public HessianServiceExporter exportHelloService() {
HessianServiceExporter exporter = new HessianServiceExporter();
exporter.setService(helloWorld);
exporter.setServiceInterface(HelloWorld.class);
return exporter;
}
}
就這樣,在不使用web.xml的情況下我們也一樣實現了spring boot和hessian服務端的集成,或者更準確的說,是spring和hessian服務端的集成。
而至於客戶端的集成,目前我還沒有整出可行的方案,因此便隻能繼續先使用之前xml文件配置的方式,引入這個xml文件然後進行後續的操作,具體的不用xml的方式還需要進一步探索,如果有朋友用過,歡迎指點和交流!
最後更新:2017-09-12 13:32:35