Spring
1.Spring
1.1 简介
- Spring是一个主流的Javaweb 开发框架,该框架是一个轻量级的业务层框架,具有很高的凝聚力和吸引力
- Spring是分层的Java SE 轻量级开源框架,它是以IOC(Inverse of Control,控制反转)和AOP(Aspect Oriented Programming,面向切面编程)为为内核,使用基本的 JavaBean 完成以前只可能由 EJB 完成的工作,取代了 EJB 臃肿和低效的开发模式。
- Spring是一个开源容器框架,它集成各类型的工具,通过核心的Bean factory实现了底层的类的实例化和生命周期的管理。在整个框架中,各类型的功能被抽象成一个个的 Bean,这样就可以实现各种功能的管理,包括动态加载和切面编程。
- Spring致力于提供一种方法管理你的业务对象。
1.2 背景
- Rod Johnson对Java EE系统框架的臃肿、低效、脱离现实的种种现状提出了质疑,并积极寻求革新的探索之道,于是他编写了interface 21框架,力图冲破Java EE传统开发的困境,从实际需求出发,着眼于轻便、灵巧,易于开发、测试和部署的轻量级开发框架。
- Spring框架即以interface21框架为基础,经过重新设计,并不断丰富其内涵,于2004年3月24日,发布了1.0正式版。
1.3 特征
- 轻量:从大小和开销来说,Spring框架都是轻量的。
- 控制反转:Spring通过一种称作控制反转(IoC)的技术促进了低耦合。当应用了IOC,一个对象所依赖的其他对象就会被动的传递进来,而并不是这个对象主动地查找依赖对象或者创建对象。
- 面向切面编程:Spring提供了面向切面编程,它将其业务逻辑与系统级服务分离开来进行内聚性的开发。也就是说它仅仅只负责完成业务逻辑,并不复杂其他系统级关注点。
- 方便集成各种优秀框架:Spring 不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如 Struts2、Hibernate、MyBatis 等)的直接支持。
- 容器:Spring包含并管理应用对象的配置和生命周期,在这个意义上它是一种容器。
1.4 Spring组成
- Spring Core:是框架最基础的部分,它提供依赖(Dependency Injection)注入来管理Bean容器功能。
- Spring Context:构建于Core包上,提供了一种框架式访问对象的方式,有些像JNDI注册。
- Spring DAO:提供了JDBC的抽象层,可消除冗长的JDBC编码和管理议程处理和不同数据供应商抛出的议程错误信息。
- Spring ORM:ORM模块提供对常用的ORM框架的管理和辅助支持。
- Spring Web:Web模块提供对常见框架如Struts1,WEBWORK(Struts 2),JSF的支持,Spring能够管理这些框架,将Spring的资源注入给框架,也能在这些框架的前后插入拦截器。
- Spring AOP:AOP包提供了符合AOP Alliance规范的面向方面的编程实现,例如方法拦截器(method-interceptors)和切点(pointcuts),从逻辑上讲,从而减弱代码的功能耦合,清晰的被分离开。
- Spring MVC: Spring 的MVC 框架是一个全功能的构建Web应用程序的MVC实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳的大量视图技术,包括JSP、Velocity、Tiles、iText和Pol。
1.5 IOC本质
控制反转其实是一种设计思想,他将原本在程序员手中的控制权反转给了用户。将其程序自动创建对象的权利变成了程序被动接受用户传入的参数。
实例:
- 没反转前:程序主动创建对象
public class Userserviceimpl implements Userservice{
@Override
public void getUser() {
new Userdaoimpl().getname();
}
}
- 反转后:程序被动接受对象
public class Userserviceimpl implements Userservice{
private Userdao userdao;
public void setUserdao(Userdao userdao) {
this.userdao = userdao;
}
@Override
public void getUser() {
userdao.getname();
}
}
小结:
- 控制反转是一种描述XML或者注解,并通过去生产或获取特定对象的方式。在Spring中实现控制反转的是IOC容器,但其实现的方法是依赖注入。个人觉得控制反转就是获取依赖对象的方式反转了,从而达到了低耦合。
2. HelloSpring
2.1 hellospring
- 实体类-Hello.class
package com.lee.pojo;
public class Hello {
private String Str;
public void setStr(String str) {
Str = str;
}
public String getStr() {
return Str;
}
@Override
public String toString() {
return "Hello{" +
"Str='" + Str + '\'' +
'}';
}
}
- 配置元数据-beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="hello" class="com.lee.pojo.Hello">
<property name="str" value="Spring"/>
</bean>
</beans>
- 测试类-MyTest.class
package com.lee;
import com.lee.pojo.Hello;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
//获取spring上下文对象
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//我们的对象现在都在spring中管理了,我们只需要从中取出来即可
Hello hello = (Hello) context.getBean("hello");
System.out.println(hello.toString());
}
}
2.2 IOC创建对象的方式
1.使用无参构造创建对象(默认)
2.使用有参构造创建对象
- 下标赋值
<bean id="hello" class="com.lee.pojo.Hello">
<!--下标赋值-->
<constructor-arg index="0" value="老李"/>
</bean>
- 类型赋值
<bean id="hello" class="com.lee.pojo.Hello">
<constructor-arg type="java.lang.String" value="老李"/>
</bean>
- 参数名赋值
<bean id="hello" class="com.lee.pojo.Hello">
<constructor-arg name="Str" value="老李"/>
</bean>
2.3 Spring配置
- 别名
<!--通过alias起别名-->
<bean id="hello" class="com.lee.pojo.Hello">
<constructor-arg name="Str" value="老李"/>
</bean>
<alias name="hello" alias="hello2"/>
- beans的配置
<!--
1.name也可以起别名,而且能起多个
2.id:bean的唯一标识,相当于我们的对象名
3.class:对象所对应的全限定名
-->
```xml
<bean id="hello" class="com.lee.pojo.Hello" name="hello3,hello4">
<constructor-arg name="Str" value="老李"/>
</bean>
- import
import一般用于团队开发使用,它可以将多个配置文件导入合并为一个,使用的时候我们直接使用总配置就可以了。
<import resource="beans1.xml"/>
<import resource="beans2.xml"/>
<import resource="beans3.xml"/>
2.4 依赖注入
依赖:bean对象的创建依赖于容器
注入:bean对象的所有属性由容器来注入
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="address" class="com.lee.pojo.Address"/>
<bean id="student" class="com.lee.pojo.Student">
<!--1.普通值注入-->
<property name="name" value="李好"/>
<!--2.bean注入-->
<property name="address" ref="address"/>
<!--3.数组注入-->
<property name="books">
<array>
<value>水浒传</value>
<value>三国演义</value>
<value>红楼梦</value>
<value>西游记</value>
</array>
</property>
<!--4.列表注入-->
<property name="hobby">
<list>
<value>看书</value>
<value>跳舞</value>
<value>放屁</value>
</list>
</property>
<!--5.map注入-->
<property name="card">
<map>
<entry key="身份证" value="123456"/>
<entry key="银行卡" value="654321"/>
</map>
</property>
<!--6.Set注入-->
<property name="game">
<set>
<value>LOL</value>
</set>
</property>
<!--7.空值注入-->
<property name="wife">
<null/>
</property>
<!--8.properties-->
<property name="info">
<props>
<prop key="学号">200822222</prop>
</props>
</property>
</bean>
</beans>
2.5 p命名空间的注入
实例:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.lee.pojo.User" p:name="老李" p:age="18"/>
</beans>
2.6 Bean作用域
重点掌握前两个!!
- 单例模式(singleton)
<bean id="accountService" class="com.something.DefaultAccountService" scope="singleton"/>
当您定义一个bean定义并且其作用域为单例时,Spring IoC容器将为该bean定义的对象创建一个实例。该单个实例存储在此类单例bean的高速缓存中,并且对该命名bean的所有后续请求和引用都返回该高速缓存的对象。通俗来说就是每一次请求容器返回的对象都是同一个对象。
2.原型模式
每次从容器中get都会产生一个新对象
<bean id="accountService" class="com.something.DefaultAccountService" scope="prototype"/>
2.7 Bean的自动装配
ByName自动装配
<bean id="cat" class="com.lee.pojo.Cat"/>
<bean id="dog" class="com.lee.pojo.Dog"/>
<bean id="people" class="com.lee.pojo.People" autowire="byName"> <!--byname:会自动在容器中查找和
自己对象set方法后面的值d对应的bean id-->
<property name="name" value="老李"/>
<!--手动装配-->
<!-- <property name="cat" ref="cat"/>-->
<!-- <property name="dog" ref="dog"/>-->
</bean>
Bytype自动装配
<bean id="cat" class="com.lee.pojo.Cat"/>
<bean id="dog" class="com.lee.pojo.Dog"/>
<bean id="people" class="com.lee.pojo.People" autowire="bytype"> <!--byname:会自动在容器中查找和
自己对象属性类型对应的bean-->
<property name="name" value="老李"/>
<!--手动装配-->
<!-- <property name="cat" ref="cat"/>-->
<!-- <property name="dog" ref="dog"/>-->
</bean>
小结:
- byname的时候,需要保证所有的bean id唯一,并且这个bean需要和主动注入的属性的set方法的值一致。
- byname的时候,需要保证所有的bean的class唯一,并且这个bean需要和主动注入的属性一致。
2.8 使用注解实现自动装配
1.导入约束:context约束
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/beans/spring-context.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/beans/spring-aop.xsd">
<!--开启注解的支持-->
<context:annotation-config/>
<bean id="cat" class="com.lee.pojo.Cat"/>
<bean id="dog" class="com.lee.pojo.Dog"/>
<bean id="people" class="com.lee.pojo.People"/>
</beans>
2.配置注解支持:context:annotation-config/
3.小结
- 直接在属性上使用@Autowired即可。
- 使用Autowired注解我们可以不用使用set方法,但前提是这个自动装配的属性在IOC容器内,且符合byname。
- 如果@Autowired的环境比较复杂,自动装配无法通过一个注解完成的时候,我们可以使用@Qualifier来配合其使用,指定唯一一个bean注入。
private String name;
@Autowired
@Qualifier(value = "dog111")
private Dog dog;
@Autowired
@Qualifier(value = "cat111")
private Cat cat;
3.代理模式
为什么要学代理模式? 因为这就是Spring AOP的底层
代理模式的分类:
- 静态代理
- 动态代理
3.1 静态代理模式
角色分析
- 抽象角色:一般使用接口或者抽象类来解决
package com.lee.pojo;
public interface Rent {
public void rent();
}
- 真实角色:被代理的角色
package com.lee.pojo;
public class Host implements Rent{
@Override
public void rent() {
System.out.println("我的房屋要出租!");
}
}
- 代理角色:代理真实角色,一般都会加一些附属操作
package com.lee.pojo;
public class Proxy implements Rent{
private Host host;
public Proxy(Host host) {
this.host = host;
}
@Override
public void rent() {
host.rent();
seehouse();
fare();
}
public void seehouse(){
System.out.println("看房!");
}
public void fare(){
System.out.println("收取中介费!");
}
}
- 客户:访问代理对象的人
package com.lee.pojo;
public class Client {
public static void main(String[] args) {
Host host = new Host();
Proxy proxy = new Proxy(host);
proxy.rent();
}
}
3.2 动态代理模式
分类
- 基于接口的动态代理—JDK动态代理
- 基于类的动态代理—cglib
4. AOP
4.1什么是AOP
- aop意为面向切面编程,通过预编译的模式或者运行期间动态代理实现程序功能的统一维护的一种功能。
4.2 AOP在spring中的作用
- 提供声明式事务,允许用户自定义切面
{{evernotecid://9DC01347-8905-4315-8627-6E807F22CB57/appyinxiangcom/31529419/ENResource/p110(uploading…)}}
4.3实现AOP的方法
使用原生spring API接口(主要是spring API接口实现)
- 导入AOP依赖包
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
- applicationCtext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="userservice" class="com.lee.Service.Userservice"/>
<bean id="afterlog" class="com.lee.Log.Afterlog"/>
<bean id="firstlog" class="com.lee.Log.Firstlog"/>
<!--配置AOP-->
<aop:config>
<!--切入点-->
<aop:pointcut id="pointcut" expression="execution(* com.lee.Service.Userservice.*(..))"/>
<aop:advisor advice-ref="firstlog" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterlog" pointcut-ref="pointcut"/>
</aop:config>
</beans>
3.firstlog.java
package com.lee.Log;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class Firstlog implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println(o.getClass().getName()+"的"+method.getName()+"被执行了!");
}
}
4.afterlog.java
package com.lee.Log;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class Afterlog implements AfterReturningAdvice {
@Override
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
System.out.println("执行了"+method.getName()+",结果为"+o);
}
}
使用自定义类(主要是切面定义)
- 自定义类
package com.lee.diy;
public class DiypointCut {
public void before(){
System.out.println("执行前!");
}
public void after(){
System.out.println("执行后!!");
}
}
- applicationCtext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="userservice" class="com.lee.Service.Userservice"/>
<bean id="afterlog" class="com.lee.Log.Afterlog"/>
<bean id="firstlog" class="com.lee.Log.Firstlog"/>
<bean id="diy" class="com.lee.diy.DiypointCut"/>
<!--配置AOP-->
<aop:config>
<!--切入点-->
<!-- <aop:pointcut id="pointcut" expression="execution(* com.lee.Service.Userservice.*(..))"/>-->
<!-- <aop:advisor advice-ref="firstlog" pointcut-ref="pointcut"/>-->
<!-- <aop:advisor advice-ref="afterlog" pointcut-ref="pointcut"/>-->
<aop:aspect ref="diy">
<aop:pointcut id="diyy" expression="execution(* com.lee.Service.Userservice.*(..))"/>
<aop:before method="before" pointcut-ref="diyy"/>
<aop:after method="after" pointcut-ref="diyy"/>
</aop:aspect>
</aop:config>
</beans>