一、Spring概述
1、概述
Spring是一个轻量级的java开发框架,为解决企业级应用开发的复杂性,简化java。spring的很多功能的底层都依赖于两个核心特性,即控制反转(IOC)和面向切面编程(AOP)。
2、Spring框架的核心
IOC容器和AOP模块,通过IOC容器管理POJO对象以及他们之间的耦合关系;通过AOP以动态注入的方式增强服务。IOC让互相协作的组件保持松散的耦合,而AOP编程允许将遍布于应用各层的功能分离出来形成可以重用的功能组件。
3、Spring的优缺点
优点
1)方便解耦,简化开发
Spring就是一个大工厂,可以将所有对象的创建和依赖关系的维护,交给Spring管理。
2)AOP编程的支持
Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能。
3)声明式事务的支持
只需要通过配置就可以完成对事务的管理,而无需手动编程。
4)方便程序的测试
Spring对Junit4支持,可以通过注解方便的测试Spring程序。
5)方便集成各种优秀框架
Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架的直接支持(如:Struts、Hibernate、MyBatis等)。
6)降低JavaEE API的使用难度
Spring对JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低。
缺点:
Spring依赖反射,反射影响性能。
4、Spring的模块组成
5、Spring框架中用到的设计模式
1)工厂模式:BeanFactory就是简单的工厂模式的体现,用来创建对象的实例。
2)单例模式:Bean默认为单例模式。
3)代理模式:Spring的AOP功能用到了JDK的动态代理和CGLIB字节码生成技术。
4)模板方法:用来解决代码重复的问题。
5)观察者模式:当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知被制动更新。如监听器。
二、Spring控制反转 IOC
1、什么是Spring IOC容器?
IoC 是指在程序开发中,实例的创建不再由调用者管理,而是由 Spring 容器创建。Spring 容器会负责控制程序之间的关系,而不是由程序代码直接控制,因此,控制权由程序代码转移到了 Spring 容器中,控制权发生了反转,这就是 Spring 的 IoC 思想。
Spring IOC 负责创建对象,管理对象(通过依赖注入(DI),装配对象,配置对象,并且管理这些对象的整个生命周期。
2、控制反转的作用
1)管理对象的创建和依赖关系的维护
2)解耦,由容器去维护具体的对象
3)动态代理
3、Spring容器创建对象的方式
1)使用默认的构造方法
<!--无参数的构造方法application.xml-->
<bean id="team01" class="com.syj.pojo.Team"></bean>
2)使用带参数的构造方法
<!--带参数的方法-->
<bean id="team02" class="com.syj.pojo.Team">
<constructor-arg name="id" value="1001"/>
<constructor-arg name="name" value="勇士"/>
<constructor-arg name="location" value="金州"/>
</bean>
3)使用工厂类
<!--工厂方法-->
<!--通过工厂类直接调用静态方法,class为MyFactory-->
<bean id="staticTeam" class="com.syj.pojo.MyFactory" factory-method="staticFun"></bean>
<!--工厂的实例方法,首先要有工厂对象,和Team一样-->
<bean id="factory" class="com.syj.pojo.MyFactory"></bean>
<!--再通过工厂的对象调用实例方法-->
<bean id="=instanceTeam" factory-bean="factory" factory-method="instanceFun"></bean>
4、基于XML的DI
1)概述
依赖注入DI:组件之间的依赖关系由容器在运行期决定,IOC和DI是同一个概念的不同角度描述,IOC是一种思想,DI是实现的手段,Spring框架使用依赖注入来实现IOC。
Spring 容器是一个超级大工厂,负责创建、管理所有的 Java 对象,这些 Java 对象被称为 Bean。
Spring 容器管理着容器中 Bean 之间的依赖关系,Spring 使用“依赖注入”的方式来管理 Bean 之间的依赖关系。使用 IoC 实现对象之间的解耦和。
2)注入分类
bean 实例在调用无参构造器创建对象后,就要对 bean 对象的属性进行初始化。初始化是由容器自动完成的,称为注入。
- 通过set方法
在service层写dao的setter方法
<bean id="teamService" class="com.syj.service.TeamService">
<!--bean实例在调用无参构造方法创建对象后,需要对bean对象的属性进行初始化-->
<!--ref引用指向teamDao的id-->
<!--设置属性 使用set方法注入-->
<property name="teamDao" ref="teamDao"></property>
</bean>
- 通过构造方法注入
<!--通过构造方法注入-->
<bean id="teamService2" class="com.syj.service.TeamService">
<constructor-arg name="teamDao" ref="teamDao"/>
</bean>
- 自动注入
设置 autowire 属性值
byName:根据名称自动注入
byType:根据类型自动注入
注:根据类型自动注入时,同源的被调用bean只能有一个。
<!--自动注入-->
<bean id="teamService3" class="com.syj.service.TeamService" autowire="byName">
</bean>
<!--自动注入,通过byType获取,只能有一个teamDao,否则找不到-->
<bean id="teamService4" class="com.syj.service.TeamService" autowire="byType">
5、基于注解实现IOC
对于DI使用注解,将不再需要Spring配置文件中声明bean实例。
1)在类上添加注解,表示该类创建对象的权限交给Spring容器。注解的属性value用于指定bean的id值,value省略时bean的id值默认为类名的首字母小写。
@Component
@Repository : 用于dao实现类的的注解
@Service: 用户service实现类的注解
@Controller: 用于controller实现类的注解
2)包扫描
需要在 Spring 配置文件中配置组件扫描器,用于在指定的基本包中扫描注解。
三、Spring的核心 AOP
1、什么是AOP?
面向切面编程,是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
AOP的作用:不修改源码的情况下,程序运行期间对方法进行功能增强
好处:
1)减少代码的重复,提高开发效率,便于维护。
2)专注核心业务的开发。
通过spring工厂自动实现将服务性代码以切面的方式加入到核心业务代码中。
2、AOP的实现机制
1)代理模式
代理:自己不做,找人帮你做。
代理模式:在一个原有功能的基础上添加新的功能。
分类:静态代理和动态代理。
2)静态代理
-
基于类的静态代理
-
基于接口的静态代理
要求:代理类和被代理类都实现了同一个接口
3)动态代理
静态代理:要求代理类一定存在,
动态代理:程序运行的时候,根据要被代理的对象动态生成代理类。
类型:
1、基于JDK的动态代理
2、基于CGLIB的动态代理
- JDK动态代理只提供接口的代理,不支持类的代理。核心InvocationHandler接口和Proxy类,InvocationHandler 通过invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起;接着,Proxy利用 InvocationHandler动态创建一个符合某一接口的的实例, 生成目标类的代理对象。
- 如果代理类没有实现 InvocationHandler 接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现AOP。CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。
public class MyJdkProxy {
public static void main(String[] args) {
TeamService teamService = new TeamService();
AOP tranAop = new TranAop();
AOP logAop = new LogAop();
//获取代理对象
IService service = (IService) new ProxyFactory(teamService,tranAop).getProxyInstance();//先有实例再调用方法
IService service1 = (IService) new ProxyFactory(service,logAop).getProxyInstance();//二级代理
service1.add();
// service.add();
}
/**
* 基于JDK的动态代理
* 结构化设计
* 提取new handler的方法和切面
* @param args
*/
public static void main1(String[] args) {
//目标对象--被代理对象
TeamService teamService = new TeamService();
AOP tranAop = new TranAop();
//返回代理对象
IService proxyService = (IService) Proxy.newProxyInstance(
teamService.getClass().getClassLoader(),
teamService.getClass().getInterfaces(),
new ProxyHandler(teamService,tranAop)
);
//被代理对象干活
proxyService.add();
System.out.println(teamService.getClass());
System.out.println(proxyService.getClass());
}
public static void main2(String[] args) {
//目标对象--被代理对象
final TeamService teamService = new TeamService();
//返回代理对象
IService proxyService = (IService) Proxy.newProxyInstance(
teamService.getClass().getClassLoader(),
teamService.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try{
System.out.println("开启事务");
Object invoke = method.invoke(teamService, args);
System.out.println("提交事务");
return invoke;
}catch (Exception e){
System.out.println("事务回滚");
}finally {
System.out.println("finally----");
}
return null;
}
}
);
//被代理对象干活
proxyService.add();
System.out.println(teamService.getClass());
System.out.println(proxyService.getClass());
}
}
public class CglibProxyFactory {
private NBAService nbaService;
private AOP aop;
public CglibProxyFactory(NBAService nbaService, AOP aop) {
this.nbaService = nbaService;
this.aop = aop;
}
public Object getInstance(){
return Enhancer.create(
nbaService.getClass(),
new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
try{
aop.before();
Object invoke = methodProxy.invokeSuper(o, objects);
aop.after();
return invoke;
}catch (Exception e){
aop.exception();
}finally {
aop.myFinally();
}
return null;
}
}
);
}
}
4)注解方式实现AOP
开发阶段:关注核心业务和AOP代码
运行阶段:spring框架会在运行的时候将核心业务和AOP代码通过动态代理的方式编织在一起
代理方式的选择:是否实现了接口:有接口就选择JDK动态代理;没有就选择CGLIB动态代理。
具体步骤
1)创建项目依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.13.RELEASE</version>
</dependency>
2)创建spring配置文件引入约束
3)创建核心业务类,实现接口
4)定义切面类
5)业务类和切面类添加注解
6)配置文件中开启包扫描和注册aspectj的自动代理
<!--扫描包-->
<context:component-scan base-package="com.syj.service,com.syj.aop"/>
<!--开启注解aop使用-->
<aop:aspectj-autoproxy proxy-target-class="true"/>