您的位置:首页 > 编程语言 > Java开发

SpringBoot系列(1)---无配置文件配置基础1

2017-07-05 21:34 846 查看
今天开始写关于SpringBoot的笔记,当然这个笔记也是主要给我自己看的。如果有其他开发者也在看我写的笔记的话,提醒一下 SpringBoot的笔记是建基于你已经熟悉使用Spring的前提地下去看的,当然我也会尽可能去重温一下Spring的东西。

关于SpringBoot 这个技术其实近段时间随着SpringCloud越来越火(所谓的微服务)SpringBoot也随着火起来了。其实Spring在3.X已经提供了纯annotation的配置,随着servlet3.0 无配置文件变得流行起来。不需要额外的WEB服务,因为WEB容器已经直接嵌入到你的项目当中,启动程序你只需要执行你写好的main方法即可启动web应用,听起来的确是挺让人兴奋的,笔者在上年 年初学习的SpringBoot,最近也准备认真研究一下SpringCloud 所以特意将SpringBoot的笔记写一下,顺便帮自己重温SpringBoot的技术。别废话马上开始····

首先我们老规矩,贴出maven 的依赖:

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>


注意如果你想加载的快,建议用Spring的repository:

<repositories>
<repository>
<id>io.spring.repo.maven.release</id>
<url>http://repo.spring.io/release/</url>
</repository>
</repositories>


聪明的你或许已经看见我有写上Aspect的依赖了,所以我们先做一下AOP的测试,关于Spring-aspects的使用,我以前有一篇详细到我自己都不知道原来写得这么详细,给出哆啦B梦的任意门:Spring
AOP 之 Aspect

一、AOP AspectJ

然后我们尝试使用Anntation注解织入和execution表达式织入的AOP

1、定义目标 annotation

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Action {
String name();
}


2、编写代织入测试的service类

@Service
public class DemoAnntationService {

@Action(name = "What the Fuck")
public void add(){
System.out.println("add executed!");
}

}

@Service
@Scope("prototype")
public class DemoMethodService {

public void add(){
System.out.println("DemoMethodService add() executed!");
}

}


3、编写织入配置类

@Aspect
@Component
public class LogAspect {

@Pointcut("@annotation(com.tony.config.Action)")
public void annotationPointCut() {
}

@After("annotationPointCut()")
public void after(JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
Action action = method.getAnnotation(Action.class);
System.out.println("注解方式拦截:" + action.name());
}

@Before("execution(* com.tony.service.DemoMethodService.add())")
public void before(JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
System.out.println("execution 拦截方式:" + method.getName());
}

}

到目前为止都是我们原来在Spring当中熟悉的东西,然后我们去掉我们应用的配置文件,使用类+annotation的方式代替配置文件的角色,由于我上面写了脏话,所以我的博客低于16岁不许看。

下面是配置:

@Configuration
@ComponentScan("com.tony")
@EnableAspectJAutoProxy
public class ApplicationConfig {

}


1、@Configuration:代表这个是一个配置类

2、@ComponentScan : 这个很熟悉了,就是扫描的类。

3、@EnableAspectJAutoProxy:启动AspectJ 动态代理。

非常简单,也没有什么难度。

运行看看:

public class App
{
public static void main( String[] args )
{
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfig.class);
DemoAnntationService anntationService = context.getBean(DemoAnntationService.class);
DemoMethodService methodService = context.getBean(DemoMethodService.class);
anntationService.add();
methodService.add();
context.close();
}
}

运行结果如下:

add executed!
注解方式拦截:What the Fuck
execution 拦截方式:add
DemoMethodService add() executed!


二、在annotation使用SpringEL

@Configuration
@ComponentScan("com.tony")
@EnableAspectJAutoProxy
//导入配置文件,但是使用这个注解需要依赖PropertySourcesPlaceholderConfigurer
@PropertySource("classpath:test.properties")
public class ApplicationConfig {

//普通注入字符串
@Value("ABC")
private String normal;

//通过systemProperties的bean获得系统名称
@Value("#{systemProperties['os.name']}")
private String osName;

//获得Spring 容器中其中一个bean的属性
@Value("#{T(java.lang.Math).random() * 100.0}")
private double randomNumber;

@Value("#{demoServiceForEL.username}")
private String serviceUsername;

//获得本地文件的resource对象
@Value("classpath:text.txt")
private Resource testFile;

//获得配置文件中的配置项
@Value("${test.propertyA}")
private String propertyA;

//获得配置文件中的配置项
@Value("${test.propertyB}")
private String propertyB;

//通过URL获得resource对象
@Value("http://www.baidu.com")
private Resource testUrl;

//这里通过environment获得property
@Autowired
private Environment environment;

//注册一个PropertySourcesPlaceholderConfigurer的Bean
@Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigure(){
return new PropertySourcesPlaceholderConfigurer();
}

public void outputResource() throws IOException {
System.out.println(normal);
System.out.println(osName);
System.out.println(randomNumber);
System.out.println(propertyA);
System.out.println(serviceUsername);
System.out.println(IOUtils.toString(testFile.getInputStream()));
System.out.println(IOUtils.toString(testUrl.getInputStream()));
System.out.println(environment.getProperty("test.propertyB"));

}

}

可以看到使用无配置文件的方式EL表达式也是如此的强大,接下来我们看看main方法:

public static void main( String[] args ) throws IOException {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfig.class);
ApplicationConfig config = context.getBean(ApplicationConfig.class);
config.outputResource();
context.close();
}

对没错,ApplicationConfig配置类本身也将会成为一个实体bean。

调用之后输出如下结果:

ABC
Mac OS X
57.69163813970949
valueA
TONY
ABCDEFG
URL调用忽略太长了.....
valueB


需要注意的是,如果我们读取文件的时候出现异常,需要添加如下的依赖支持:

<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>


三、使用配置类方式配置bean

刚刚上面已经看见了,除了常规的annotation配置bean的方式,也可以使用以下这种方式:

public class BeanWayService {

public void init(){
System.out.println("BeanWayService-init");
}

public BeanWayService(){
System.out.println("BeanWayService-constructor");
}

public void destroy(){
System.out.println("BeanWayService-destroy");
}

}

没有配置任何的@Service @Repository 等标签

@Configuration
@ComponentScan("com.tony")
@EnableAspectJAutoProxy
public class ApplicationConfig {

@Bean(initMethod = "init",destroyMethod = "destroy")
public BeanWayService beanWayService(){
return new BeanWayService();
}

}

上面应该都懂了,先初始化的时候调用init方法,在销毁的时候调用destroy方法。注意:虽然我们没有在代码上显性定义为单例,但是事实上是单例:

public static void main( String[] args ) throws IOException {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfig.class);
BeanWayService wayServiceA = (BeanWayService) context.getBean("beanWayService");
BeanWayService wayServiceB = (BeanWayService) context.getBean("beanWayService");
System.out.println(wayServiceA == wayServiceB);
context.close();
}

运行输出如下:

BeanWayService-constructor
BeanWayService-init
true
BeanWayService-destroy


当然我们也可以定义他的scope,下面是两个定义scope的方法:

@Configuration
@ComponentScan("com.tony")
@EnableAspectJAutoProxy
public class ApplicationConfig {

@Bean(initMethod = "init",destroyMethod = "destroy")
@Scope("prototype")
public BeanWayService wayService(){
return new BeanWayService();
}

}

Main方法:

public static void main( String[] args ) throws IOException {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfig.class);
BeanWayService wayServiceA = (BeanWayService) context.getBean("wayService");
BeanWayService wayServiceB = (BeanWayService) context.getBean("wayService");
System.out.println(wayServiceA == wayServiceB);
context.close();
}

可能你已经发现,我定义bean的方法的方法名改了,相对应的我在main方法当中的bean名称也发生了改变,由此得出定义bean的方法名其实就是定义bean的id

以下是运行结果:

BeanWayService-constructor
BeanWayService-init
BeanWayService-constructor
BeanWayService-init
false


如果是使用annotation定义bean的话,我们只需要在类中打上@Scope标签即可:

@Service
@Scope("prototype")
public class DemoServiceForEL {
public String username = "TONY";
}


四、使用Profile

profile的主要作用是,当我们需要在不同环境当中获得不同的配置,或者不同的环境中获得不同的bean,这个时候就可以使用Profile。

设置当前的Profile有如下3种方式:

1、通过Environment的ActiveProfiles 设置当前的context的环境。

2、通过JVM的spring.profiles.active参数来进行指定context的环境。

3、WEB项目通过Servlet中的context parameter进行设置

3.1 servlet2.5以下:在DispatcherServlet 中的init-param标签,添加spring.profiles.active的配置。

3.2 servlet3.0以上:在ServletContext 对象中setInitParameter("spring.profiles.default","当前环境字符串") 进行配置。

由于我当前不是web项目,所以我使用第一种方式进行演示:

定义个demoBean类:

public class DemoBean {
private String content;
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public DemoBean(String content) {
this.content = content;
}
}

配置类如下:

@Configuration
@ComponentScan("com.tony")
@EnableAspectJAutoProxy
public class ApplicationConfig {

@Profile("dev")
@Bean("demoBean")
public DemoBean devDemoBean(){
return new DemoBean("DEV");
}

@Profile("prod")
@Bean("demoBean")
public DemoBean prodDemoBean(){
return new DemoBean("PROD");
}

}

可以看见我使用了@Profile指定了不同环境的名称,由于我们不可能写两个相同方法名称的方法,所以我们使用了@Bean中的name属性去定义bean的名称。

main方法:

public class App
{
public static void main( String[] args ) throws IOException {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.getEnvironment().setActiveProfiles("dev");
context.register(ApplicationConfig.class);
context.refresh(); //记得刷新一下配置
DemoBean demoBean = (DemoBean) context.getBean("demoBean");
System.out.println(demoBean.getContent());
}
}

我们一开始在AnntationConfigApplicationContext的构成中并没有去定义具体的配置类,获得contex对象之后更改profile 然后注册ApplicationConfig配置类,然后刷新配置。以下是运行结果:

DEV
如果换环境只需要我们将setActiveProfiles修改为prod即可。

五、事件

如果有android开发经验的同学应该已经有用过EventBus了,而Spring中的事件与ANDROID中的EventBus非常相似。Spring中的事件主要提供多个bean进行某个Event的事件监听。以下就开始上代码:

1、我们需要继承ApplicationEvent定义自定义事件

public class DemoEvent extends ApplicationEvent {

private String msg;

public String getMsg() {
return msg;
}

public void setMsg(String msg) {
this.msg = msg;
}

public DemoEvent(Object source,String msg) {
super(source);
this.msg = msg;
}

}


2、创建需要监听事件的类,需要实现ApplicationListener接口

@Component
public class DemoListener implements ApplicationListener<DemoEvent> {

public void onApplicationEvent(DemoEvent demoEvent) {
String msg = demoEvent.getMsg();
System.out.println("got a message from <"+demoEvent.getSource().getClass().toString()+"> :" + msg);
}
}

3、创建发送事件的类

@Component
public class DemoPublisher {

@Autowired
ApplicationContext applicationContext;

public void publish(String msg){
applicationContext.publishEvent(new DemoEvent(this,msg));
}

}

4、main方法调用并输出如下结果:

public class App
{
public static void main( String[] args ) throws IOException {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfig.class);
DemoPublisher publisher = context.getBean(DemoPublisher.class);
publisher.publish("ABC");
}
}


输出:got a message from <class com.tony.event.DemoPublisher> :ABC

注意:事实上我们监听事件可以不止一个监听事件的bean,所有继承并监听DemoEvent的类对象都会获得事件消息。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  SpringBoot JAVA AOP EVENT