Spring java bean 配置
Java 配置是通过 @Configuration和 @Bean来实现的:
如下:此处没有使用@Service声明 Bean。使用功能类的 Bean。
//1
package com.example.springboot;
/**
* @Author: hyh
* @Date: 2021/10/7 11:31
**/
public class Bean1 {
public String say(){
return "Hello";
}
}
//2
package com.example.springboot;
/**
* @Author: hyh
* @Date: 2021/10/7 11:31
**/
public class Bean2 {
Bean1 bean1;
public void setBean1(Bean1 bean1) {
this.bean1 = bean1;
}
public String say(){
return bean1.say();
}
}
//3
package com.example.springboot;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Author: hyh
* @Date: 2021/10/7 11:34
* 使用@Configuration注解表明当前类是一个配置类,这意味着这个类里可能有0个或者多个@Bean注解,
* 此处没有使用包扫描,是因为所有的Bean都在此类中定义了。
**/
@Configuration
public class BeanConfig {
// 使用@Bean 注解声明当前方法bean1 的返回值是一个 Bean,Bean的名称是 方法名
@Bean
public Bean1 bean1(){
return new Bean1();
}
@Bean
public Bean2 bean2(){
Bean2 bean2 = new Bean2();
bean2.setBean1(bean1());
return bean2;
}
// 通过 bean 注解返回实例对象,同时可将bean 实例作为参数传递
@Bean
public Bean2 bean2(Bean1 bean1){
Bean2 bean2 = new Bean2();
bean2.setBean1(bean1);
return bean2;
}
}
//4 测试
package com.example.springboot;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import java.io.IOException;
/**
* @Author: hyh
* @Date: 2021/10/6 15:12
**/
@Configuration
@ComponentScan("com.example.springboot")
public class Test {
public static void main(String[] args) {
// 接收一个配置类的容器
AnnotationConfigApplicationContext context
= new AnnotationConfigApplicationContext(Test.class);
Bean2 bean = context.getBean(Bean2.class);
System.out.println(bean.say());
}
}
输出:
Hello
AOP
AOP:面向切面编程,相对于OOP面向对象编程。
Spring 的 AOP的存在目的是为了解耦。AOP可以让一组类共享相同的行为。在 OOP中只能通过继承类和实现接口,来使代码的耦合度增强,且类继承只能为单继承,阻碍更多行为添加到一组类上,AOP弥补了OOP的不足。
Spring支持 AspectJ的注解式切面编程:
其中符合条件的每一个被拦截处为连接点(JoinPoint)。
// 1 切面注解定义
package com.example.springboot;
import java.lang.annotation.*;
/**
* @Author: hyh
* @Date: 2021/10/7 14:19
**/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LogAop {
String log();
}
// 2 要切的方法上加上注解
package com.example.springboot;
import org.springframework.stereotype.Service;
/**
* @Author: hyh
* @Date: 2021/10/7 14:22
**/
@Service
public class LogService {
@LogAop(log = "添加")
public void add(){
System.out.println("执行了添加");
}
}
// 定义切面进行逻辑处理
package com.example.springboot;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
/**
* @Author: hyh
* @Date: 2021/10/7 14:24
**/
@Aspect
@Component
public class LogAspect {
/**
* 设置操作日志切入点 记录操作日志 在注解的位置切入代码
*/
@Pointcut("@annotation(com.example.springboot.LogAop)")
public void pointCut() {
}
// // 配置连接点 方法开始执行时通知
// @Before(value = "pointCut()")
// public void beforeLog(JoinPoint joinPoint) {
// System.out.println("开始执行前置通知");
// }
// // 方法执行完后通知
// @After(value = "pointCut()")
// public void afterLog(JoinPoint joinPoint) {
// System.out.println("开始执行后置通知");
// }
//
// // 抛出异常后通知
// @AfterThrowing(value = "pointCut()")
// public void afterThrowingLog(JoinPoint joinPoint) {
// System.out.println("方法抛出异常后执行通知");
// }
//
// // 环绕通知
// @Around(value = "pointCut()")
// public void aroundLog(ProceedingJoinPoint joinPoint) throws Throwable {
// System.out.println("环绕通知开始 日志记录");
// Object proceed = joinPoint.proceed();
// System.out.println("环绕通知结束 日志记录");
// }
/**
* 连接点执行完成后 执行此方法 如果抛出异常不执行
* @param joinPoint
*/
@After(value = "pointCut()")
public void AddLog(JoinPoint joinPoint){
// 从切面织入点处通过反射机制获取织入点处的方法
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
// 获取切入点所在的方法
Method method = signature.getMethod();
// 获取方法名
String methodName = method.getName();
// 获取操作
LogAop opLog = method.getAnnotation(LogAop.class);
String log = opLog.log();
System.out.println(methodName + ": "+ log);
}
}
Spring Scope
Scope描述的是Spring 容器如何新建 Bean的实例的。Spring 的 Scope有以下几种,通过@Scope注解来实现。
/**
* @Author: hyh
* @Date: 2021/10/7 14:22
**/
@Service
@Scope("prototype") // 不写默认为单例
public class LogService {
@LogAop(log = "添加")
public void add(){
System.out.println("执行了添加");
}
}
Spring EL 和资源调用
Spring 开发中经常涉及调用各种资源的情况,包含普通文件、网址、配置文件、系统环境变量等,我们可以使用 Spring的表达式语言实现资源的注入。
Spring主要在注解@Value的参数中使用表达式。
package com.example.springboot;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.*;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.env.Environment;
import org.springframework.core.io.Resource;
import java.io.IOException;
/**
* @Author: hyh
* @Date: 2021/10/6 11:24
**/
@Configuration
@ComponentScan("com.example.springboot")
@PropertySource("classpath:application.properties")
public class ELDemo {
@Value("注入字符串")
private String name1;
@Value("#{T(java.lang.Math).random() * 100}")
private String name3;
@Value("${book.author}")
private String name4;
@Value("www.baidu.com")
private Resource name5;
@Value("classpath:application.properties")
private Resource name6;
@Autowired
private Environment e;
@Bean
public static PropertySourcesPlaceholderConfigurer propertyConfig(){
return new PropertySourcesPlaceholderConfigurer();
}
public void print() throws IOException {
System.out.println(name1);
System.out.println(name3);
System.out.println(name4);
System.out.println(name5);
System.out.println(IOUtils.toString(name6.getInputStream()));
System.out.println(e.getProperty("book.author"));
}
}
package com.example.springboot;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @Author: hyh
* @Date: 2021/10/6 15:12
**/
@Configuration
@ComponentScan("com.example.springboot")
public class Test {
public static void main(String[] args) throws IOException {
AnnotationConfigApplicationContext context = new
AnnotationConfigApplicationContext(Test.class);
ELDemo bean = context.getBean(ELDemo.class);
bean.print();
context.close();
}
}
输出:
注入字符串
18.311029337659402
wangfei
class path resource [www.baidu.com]
book.author=wangfei
book.name=Spring Boot
15:33:41.096 [main]DEBUG org.springframework.core.env.PropertySourcesPropertyResolver
-Found key 'book.author' in PropertySource
'class path resource [application.properties]'with value of type String
wangfei
Bean 的初始化和销毁
在我们实际开发的时候,经常会遇到在 Bean 在使用之前或者之后做些必要的操作,Spring对Bean的生命周期的操作提供了支持。在使用Java配置和注解配置下提供如下两种方式:
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>jsr250-api</artifactId>
<version>1.0</version>
</dependency>
package com.example.springboot;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
/**
* @Author: hyh 用注解方式
* @Date: 2021/10/27 15:45
**/
public class BeanWay {
// 在构造函数执行完之后
@PostConstruct
public void init(){
System.out.println("init");
}
public void doing(){
System.out.println("doing");
}
// 在Bean 销毁之前
@PreDestroy
public void destroy(){
System.out.println("destroy");
}
}
package com.example.springboot;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Author: hyh
* @Date: 2021/10/27 15:50
**/
@Configuration
public class BeanWayConf {
@Bean
public BeanWay bean1(){
return new BeanWay();
}
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new
AnnotationConfigApplicationContext(BeanWayConf.class);
BeanWay bean1 = context.getBean(BeanWay.class);
bean1.doing();
context.close();
}
}
输出:
init
doing
destroy
--------------------------------------------------------------------------------
package com.example.springboot;
/**
* @Author: hyh 用 java配置方式
* @Date: 2021/10/27 15:45
**/
public class BeanWay {
// 在构造函数执行完之后
public void init(){
System.out.println("init");
}
public void doing(){
System.out.println("doing");
}
// 在Bean 销毁之前
public void destroy(){
System.out.println("destroy");
}
}
package com.example.springboot;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Author: hyh
* @Date: 2021/10/27 15:50
**/
@Configuration
public class BeanWayConf {
@Bean(initMethod = "init", destroyMethod = "destroy")
public BeanWay bean1() {
return new BeanWay();
}
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new
AnnotationConfigApplicationContext(BeanWayConf.class);
BeanWay bean1 = context.getBean(BeanWay.class);
bean1.doing();
context.close();
}
}
输出:
init
doing
destroy
Profile
Profile为在不同环境下使用不同的配置提供了支持(开发环境下的配置和生产环境下的配置肯定是不同的,例如,数据库的配置)。
package com.example.springboot;
import lombok.Data;
/**
* @Author: hyh
* @Date: 2021/10/7 11:31
**/
@Data
public class Bean1 {
private String str;
public String say() {
return "str";
}
public Bean1(String str){
this.str = str;
}
public Bean1( ){
}
}
package com.example.springboot;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
/**
* @Author: hyh
* @Date: 2021/10/30 10:53
**/
@Configuration
public class ProfileConfig {
@Bean
@Profile("dev")
public Bean1 ben1(){
return new Bean1("dev");
}
@Bean
@Profile("test")
public Bean1 ben2(){
return new Bean1("test");
}
}
package com.example.springboot;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @Author: hyh
* @Date: 2021/10/6 15:12
**/
@Configuration
@ComponentScan("com.example.springboot")
public class Test {
public static void main(String[] args) throws IOException {
AnnotationConfigApplicationContext context = new
AnnotationConfigApplicationContext();
context.getEnvironment().setActiveProfiles("dev");
context.register(ProfileConfig.class);
context.refresh(); //需要刷新容器
Bean1 bean1 = context.getBean(Bean1.class);
System.out.println(bean1.getStr());
context.close();
}
}
输出:
dev
事件
Spring的事件(Application Event)为Bean与 Bean 之间的消息通信提供了支持。当一-个Bean处理完一个任务之后,希望另外一个 Bean知道并能做相应的处理,这时我们就需要让另外一个 Bean 监听当前Bean所发送的事件。
Spring 的事件需要遵循如下流程:
(1) 自定义事件,集成ApplicationEvent。
(2)定义事件监听器,实现ApplicationListener。
(3)使用容器发布事件。
package com.example.springboot.event;
import lombok.Getter;
import lombok.Setter;
import org.springframework.context.ApplicationEvent;
/**
* @Author: hyh
* @Date: 2021/11/1 9:19
**/
@Setter
@Getter
public class MyEvent extends ApplicationEvent {
private String msg;
public MyEvent(Object source, String msg) {
super(source);
this.msg = msg;
}
}
package com.example.springboot.event;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
/**
* @Author: hyh
* @Date: 2021/11/1 9:23
**/
@Component
public class MyEvListener implements ApplicationListener<MyEvent> {
@Override
public void onApplicationEvent(MyEvent event) {
String msg = event.getMsg();
System.out.println("监听到消息:" + msg);
}
}
package com.example.springboot.event;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
/**
* @Author: hyh
* @Date: 2021/11/1 14:58
**/
@Component
public class MyPublish {
@Autowired
ApplicationContext ac;
public void send (String msg){
ac.publishEvent(new MyEvent(this,msg));
}
}
package com.example.springboot;
import com.example.springboot.event.MyPublish;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* @Author: hyh
* @Date: 2021/10/6 15:12
**/
@Configuration
@ComponentScan("com.example.springboot.event")
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new
AnnotationConfigApplicationContext(Test.class);
MyPublish bean1 = context.getBean(MyPublish.class);
bean1.send("发送消息");
context.close();
}
}
输出:
监听到消息:发送消息
下一章:day002