Spring框架本身四大原则
1.使用POJO进行轻量级以及最小侵入式开发
2.通过依赖注入和基于接口式编程实现松耦合
3.通过AOP和默认习惯进行声明式编程
4.使用AOP和模板(template)减少模式化代码
控制反转和依赖注入在Spring环境下市等同的概念。
常用配置
Bean的Scope
描述Spring如何新建Bean的实例,与模式相似,由@Scope注解实现。如:@Scope("singleton")/prototype等。
Singleton:单例模式,全容器共享一个Bean实例
Prototype:非单例模式,每次调用新建一个Bean实例
Request:Web项目中,给每一个http Request新建一个Bean实例
Session:Web项目中,给每一个http Session新建一个Bean实例
GlobalSession:这个只在portal(?)应用中有用,给每一个global http Session新建一个Bean实例
singleton
@Service
//@Scope("singleton")
public class SingletonService(){
}
prototype
@Service
@Scope("prototype")
public class PrototypeService(){
}
//配置类
@Configuration
@ComponentScan("所在包名")
public class ScopeConfig(){
}
public class Main {
public static void main(String[] args){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ScopeConfig.class);
DemoSingletonService singletonService1 = context.getBean(DemoSingletonService.class);
DemoPrototypeService prototypeService1 = context.getBean(DemoPrototypeService.class);
DemoSingletonService singletonService2 = context.getBean(DemoSingletonService.class);
DemoPrototypeService prototypeService2 = context.getBean(DemoPrototypeService.class);
String s1_s2 = singletonService1==singletonService2?"是":"否";//equals也可以
String p1_p2 = prototypeService1==prototypeService2?"是":"否";
System.out.println("singletonService1 与 singletonService2 是否为同一个Bean实例:"+s1_s2);
System.out.println("prototypeService1 与 prototypeService2 是否为同一个Bean实例:"+p1_p2);
int[] nums = new int[20];
for (int i=0;i<nums.length; i++)
System.out.println(nums[i]);
}
EL和资源调用
在注解中使用Spring-EL表达式,和JSP中EL表达式使用类似
可参考https://blog.csdn.net/acmjk/article/details/46791603
实例:在自己定义的一个目录下新建一个test.txt文件(内容随便)和test.properties文件
需要用到的简化文件操作,事先引用
<!--简化文件相关操作 可将file转换为字符串-->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.3</version>
</dependency>
<!--test.properties文件内容-->
book.name = spring boot
book.author = writor
/**
*定义一个Service(Bean)实例,用于演示el表达式注入其他Bean的属性
*/
@Service
public class DemoService{
private String fromOtherBean;
public String getFromOtherBean(){
return fromOtherBean;
}
public void getFromOtherBean(String another){
this.fromOtherBean= another;
}
}
配置类
@Configuration
@ComponentScan("com.wisely.highlight_spring4_idea.ch2.el")
@PropertySource("classpath:com/wisely/highlight_spring4_idea/ch2/el/test.properties")
//用PropertySource注入配置文件
public class ElConfig{
@Value("普通字符串")
private String normal;//注入普通字符串
@Value("#{systemProperties['os.name']}")//注入操作系统属性
private String osName;
@Value("#{T(java.lang.Math).random()*100.0}")//注入表达式结果
private double randomNum;
@Value("#{demoService.fromAnotherBean}")//注入其他Bean属性
private String fromAnother;
//若使用@Value注入需要PropertySourcesPlaceholderConfigurer的Bean
@Value("classpath:com/wisely/highlight_spring4_idea/ch2/el/test.txt")//注入文件资源
private Resource testFile;
@Value("http://www.baidu.com")//注入网址资源
private Resource testUrl;
@Value("${book.name}")//注入配置文件
private String bookName;
@Autowired
private Environment environment;//注入配置文件 properties可从Environment中获得
@Bean//若使用@Value注入需要PropertySourcesPlaceholderConfigurer的Bean
public static PropertySourcesPlaceholderConfigurer propertyConfig(){
return new PropertySourcesPlaceholderConfigurer ();
}
public void outputResource(){
try {
System.out.println(normal);
System.out.println(osName);
System.out.println(randomNum);
System.out.println(fromAnother);
System.out.println(IOUtils.toString(testFile.getInputStream()));
System.out.println(IOUtils.toString(testUrl.getInputStream()));
//本人测试为null,正在查找原因
System.out.println(bookName);
//System.out.println(bookAuthor);
System.out.println(environment.getProperty("book.author"));
}catch (Exception e){
e.printStackTrace();
}
}
}
Main(本人按教材例子和IDEA实现,经常报test.properties文件不存在错误,但是文件路径没错,且在找到文件后读出打印数据又为null)
public class Main{
public static void main(String[] args){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ElConfig.class);
ElConfig resorceService = context.getBean(ElConfig.class);
resorceService.outputResource();
context.close(); }
}
错误原因和解决:
编译后配置文件没带过去,这是使用IDEA时会遇到的错误。
用的是IDEA,会发现target文件夹里只有class没有properties和txt。
手动复制过去或者把properties放在resource里就可以了。后者是默认地址就不用加前面的路径了。
(但是复制在resource中时,我仍然会报这个错误,而复制在target里的就不会报错)
原因网上有说是:
对于MAVEN项目,Eclipse会自动把项目src\main\java\目录下的配置文件(.xml)和资源文件(.properties)搬运到target目录下,而intellij idea默认是不会帮我们做这件事的。
Bean的初始化和销毁
即定义在Bean的使用之前和之后需要做的操作
(1)java配置方式:使用@Bean的init()和destroy()方法
(2)注解:在定义的方法前使用JSR-250的@PostCustruct和@PreDestroy,注解需要引入
<!--增加JSR250支持-->
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>jsr250-api</artifactId>
<version>1.0</version>
</dependency>
public class BeanWayService {
public void init(){
System.out.println("@Bean-init-method");
}
public BeanWayService(){
super();
System.out.println("初始化构造函数-BeanWayService");
}
public void destory(){
System.out.println("@Bean-destory-method");
}
}
public class JSR250WayService {
@PostConstruct//构造函数执行之后执行
public void init(){
System.out.println("jsr250-init-method");
}
public JSR250WayService(){
super();
System.out.println("初始化构造函数:JSR250WayService");
}
@PreDestroy//Bean销毁之前执行
public void destory(){
System.out.println("jsr250-destory-method");
}
}
@Configuration
@ComponentScan("com.wisely.highlight_spring4_idea.ch2.prepost")
public class PrepostConfig {
@Bean(initMethod = "init",destroyMethod = "destory")//指定BeanWayService类的init和destory在构造之后、Bean销毁之前执行
BeanWayService beanWayService(){
return new BeanWayService();
}
@Bean
JSR250WayService jsr250WayService(){
return new JSR250WayService();
}
}
public class Main {
public static void main(String[] args){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(PrepostConfig.class);
BeanWayService beanWayService = context.getBean(BeanWayService.class);
System.out.println("----------");
JSR250WayService jsr250WayService = context.getBean(JSR250WayService.class);
context.close();
}
}
Profile
版本控制
//模拟Bean
public class DemoBean{
String msg;
public DemoBean(String msg){
super();
this.msg = msg;
}
public void setMsg(String msg){
this.msg = msg;
}
public String getMsg(){
return msg;
}
}
/**
*关键配置
*/
@Configuration
public class ProfileConfig{
@Bean
@Profile("dev")//环境配置 Profile为dev时实例化devDemoBean
public DemoBean devDemoBean(){return new DemoBean("Profile-dev:devDemoBean")}
@Bean
@Profile("pre")
public DemoBean preDemoBean(){return new DemoBean("Profile-pre:preDemoBean")}
}
Main方法中
public class Main{
public static void main(String[] args){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.getEnvironment().setActiveProfiles("pro");//将活动的profile设置为"pre"
context.register(ProfileConfig.class)//后置注册Bean配置类,否则会报Bean未定义错误
context.refresh();//刷新容器
DemoBean bean = context.getBean(DemoBean.class);
System.out.println(bean.getMsg);
context.close();
}
}
Event
自定义事件继承ApplicationEvent(类+方法)-->定义事件监听器实现ApplicationListener接口并指定监听的事件类型ApplicationListener<T>(加入Spring容器管理)-->定义事件发布类,注入ApplicationContext用来发布事件(加入Spring容器管理)
public calss DemoEvent extends ApplicationEvent{
private String msg;
public DemoEvent(Object source,String msg){
super(source);
this.msg = msg;
}/*若没有自带属性,则构造函数只初始化父类Object source属性
public DemoEvent(Object source){
super(source);
}*/
public String getMsg() { return msg; }
public void setMsg(String msg) { this.msg = msg; }
}
@Component
public class DemoEventListener implements ApplicationListener{
@Override
public void onApplicationEvent(Event1 event) {
System.out.println("监听器 接收发布消息:"+event.getMsg);
}
}
@Component
public class DemoEventPubisher{
@Autowired
ApplicationContext applicationContext;//注入ApplicationContext用来发布事件
public void publish(String msg){
applicationContext.publishEvent(new Event(this,msg));
}
}
public class Main {
public static void main(String[] args){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(EventConfig.class);
DemoPublisher publisher = context.getBean(DemoPublisher.class);
//Event1Publisher event1 = context.getBean(Event1Publisher.class);
publisher.publish("我爱你");
//event1.pubish("I Love You");
context.close();
}
}