Spring两大核心:IOC、DI
IOC:控制反转,程序员将对象的实例化工作完全交给框架,需要对象时只要去框架的容器内(BeanFactory/ApplicationContext)申请即可。(但是如何实例化依然需要程序员告诉容器)
最基本的IOC:
很清楚,创建一个ApplicationContext容器,通过容器的getBean方法获取对象实例。
Windows上必须加上context.registerShutdownHook();来确保销毁容器
而容器是根据xml中的配置进行具体的实例化工作
这是最基本的xml,bean表示一个类,id用于依赖注入,也就是一个在xml内使用的变量名,class是类本名,property是类变量,value可以依赖于别的bean
scope用来指明是否单例模式
Spring容器有三种配置方法:xml、注解、基于Java
配置类初始化和销毁方法
init-method/destroy-method,可以用来代替构造函数
如果有很多个类都是init和destroy这两个名字作为初始化和销毁方法,可以配置默认方法
定义继承:
显然abstract不能被实例化,而parent声明继承关系,如果有参数被缺省初始化,那么会自动继承父类对应变量值,否则为null,如helloIndia::message2="Hello Second World!"
DI:依赖注入,显然当我们不用框架编写程序时,每个成熟的类都需要依赖或多或少的其他工具类,那么可重用性就不高。
例如这就是通常情况下我们使用其他工具类的方法:自己进行初始化。然而,一旦换到其他应用环境,可能SpellChecker初始化就需要增加一些额外的参数而不是无参数初始化,这时就不得不回来修改TextEditor的源码。
可是在Spring下,可以这么写。在TextEditor的初始化时直接传入一个spellChecker实例(依赖注入),这下就方便了,遇到不同环境,只需要去xml文件里面更改spellChecker的初始化方式就行了,源码并不需要作修改。
上面这种DI方法叫做基于构造函数的依赖注入,他的xml要这么写
<constructor-arg ref=" "/>用来指明构造函数参数的依赖注入,ref表明这是一个引用其他bean类的参数
同样也可以根据参数类型和索引来注入依赖
基于设值函数的依赖注入:
其实就是用若干个setXXX函数来代替构造函数了
在xml里面也从<constructor-arg ref=" "/>变成了<property name=" " ref=" "/>,不难理解
p:参数名=" " 直接的值
p:参数名-ref=" " 引用的值
同样也有cnamespace,指代constructor-arg,都是用来简化xml编写,主要这里的p/c属性都在bean标签内
使用方法:引入命名空间
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
上面的代码不变,还可以这么写xml,称为内部类依赖注入
区别就在于peoperty标签内再起一个bean标签,表明这是作为内部类注入的依赖
基于工厂方法(接口)注入:
注入集合:
空串:"" 空值:<null/>
自动装配
上述的依赖注入非常清晰,但同时也相当繁琐,Spring容器通过自动装配来简化我们的xml编写
使用方法是指定bean标签的autowire属性模式
先看正常情况下的xml:
byName模式下的autowire编写:
可以看到,autowire被声明为byName模式。而且省去了对spellChecker的引用:因为这个模式下容器会自动在xml里寻找和这个名字一样的bean注入依赖。显然要想使用byName模式,在类成员的命名和xml的标签命名上要一致,否则容器是找不到的。
byType模式下的依赖注入:
这里的要求就更松了:如果类成员只有一个SpellChecker类型,那么名字都可以随便起,容器只要类型匹配即可
constructor模式
不使用set方法而是用构造函数
以上都是通过xml文件进行配置,还可以用注解来配置:
新增三个context相关的bean属性以及<context:annotation-config/>启用注解
注:xml优先级高于注解,会覆盖
@Required放在setXXX方法上,表明该XXX成员不可缺省,必须在xml中进行初始化指定
@Autowired 自动装配:会给注释在setter方法上的成员进行byType模式自动装配,如果没有setter方法,也可以在成员声明上直接注释,会自动创建setter方法,放在构造函数上也可以
@Autowired(required=false)告诉编译器,即使没有找到匹配的bean也不报错
@Qualifier(" A ")用来配合Autowired进行自动装配,告诉容器要去寻找id为"A"的bean进行装配
@PostConstruct 和 @PreDestroy 放在init和destory上,省去xml配置
@Resource类似@Autowired,但他是byName的 @Resource(name= "spellChecker")
AOP:面向方面编程
Spring下mvc相关的配置:
Controller相当于告诉容器这是个能处理事件的函数,RequestMapping则声明url链接以及http头里面的方法是哪种类型(一般是GET或者POST)。ResponseBody!!当你想返回html以外格式的文件时(比如String、JSON等),就必须用这个注释,这里我们要返回一个Map,但显然单单一个Map传到网页前端可不会自动帮我们转换到JSON。
还需要在servlet的xml文件中添加一行:viewClass,告诉网页用JstlView来解析这个Map,接下来我们就能在网页上看到合适的结果了。在这个上面还要添加mvc注释驱动
接下来服务器是没问题了,那么客户端呢?
先来看我写的一个测试客户端
用的是java自带的httpURLConnection,这没问题,你想用httpclient也行。总之,进行一些必要的参数设置之后,我们connect并准备要去输入字节流里面获取服务器返回的信息了。注意,不要用字节数组读入,我本来使用字节数组读入,然后发现结果非常的奇怪,比如JSON字符串在网页上还显示正常,一读过来就格式错误---->特别多无意义的空格。解决办法呢也很简单,就是用BufferedReader去读取,并且声明是“UTF-8”格式,这下能够正常读入了,下面是客户端输出的字符串。
ps.用Postman调试比自己写客户端调试更好
请求url的参数名和控制器的形参名一致的话,可以不用加@RequestParam
SpringAOP没效果的原因:
如果对Controller进行环绕,就要到映射到该Controller方法的servletName-servlet.xml中设置AOP自动代理
比如下面这个
就要到 learn_test-servlet.xml中设置
ok
环绕方法中获取客户端发来参数: