1 Sping简单介绍
1.1 Spring是什么
Spring 是分层的 Java SE/EE 应用 full-stack 轻量级开源框架,以 IoC(Inverse Of Control:反转控制)和 AOP(Aspect Oriented Programming:面向切面编程)为内核,提供了展现层 Spring
MVC 和持久层 Spring JDBC 以及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多著名的第三方框架和类库,逐渐成为使用最多的 Java EE 企业应用开源框架。
1.2 Spring的优势
1.2.1 方便解耦,简化开发
通过 Spring 提供的 IoC 容器,可以将对象间的依赖关系交由 Spring 进行控制,避免硬编码所造成的过度程序耦合。用户也不必再为单例模式类、属性文件解析等这些很底层的需求编写代码,可以更专注于上层的应用。
1.2.2 AOP(面向切面编程)编程的支持
通过 Spring 的 AOP 功能,方便进行面向切面的编程,许多不容易用传统 OOP 实现的功能可以通过 AOP 轻松应付。(例如打印日志、性能监控、事务管理、安全验证等等)。
1.2.3 声明式事务的支持
可以将我们从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活的进行事务的管理,提高开发效率和质量。
1.2.4 方便程序的测试
可以用非容器依赖的编程方式进行几乎所有的测试工作,使测试更容易实现。
1.2.5 方便集成各种优秀框架
Spring 可以降低各种框架的使用难度,提供了对各种优秀框架(Struts、Hibernate、Hessian、Quartz等)的直接支持。
1.3 Spring的体系结构
2 IOC
2.1 IOC(Inversion Of Control)
降低程序之间的耦合度(解耦)的思路有两种。一种是使用工厂模式,另一种就是Spring的IOC(控制翻转)。IOC将控制权从调用的类转换到了Spring的IOC容器,有Spring的IOC容器来创建实例和依赖注入。
2.2 IOC的配置方式
2.2.1 xml方式配置
下面以Idea为例具体说明。
首先新建一个Maven工程。在pom.xml文件中加入Spring依赖。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
在src>main文件夹下面新建resources文件夹,新建以 .xml结尾的配置文件。配置文件初始内容包括beans标签和xmlms。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
</beans>
bean标签
bean的概念: 在计算机英语中,bean有可重复使用的组件的含义。Java Bean 指用Java语言编写的课重用组件。
作用: 用于配置对象让Spring来创建的。默认情况下它调用的是类中的无参构造函数,如果没有无参构造函数则不能创建成功。
属性:
id 给对象在容器中提供一个唯一标识,用于获取对象。
class 指定类的权限定类名。用于反射创建对象。
scope 指定对象的作用范围。作用范围如下:
- singleton:单例对象,默认值
- prototype:多例的或者原型
- request:WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 request 域中
- session:WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 session 域中
- globelSession:WEB 项目中,应用在 Portlet 环境.如果没有 Portlet 环境那么globalSession 相当于 session
init-method 指定类中的初始化方法名称
destroy-method指定类中的销毁方法名称
bean标签代码示例:
<bean id="UserDao" class="com.xxxx.spring.dao.impl.UserDaoImpl"></bean>
bean的生命周期和作用域
单例对象:singleton
一个应用只有一个对象的实例。他的作用范围就是整个引用。
生命周期:
对象出生:当应用加载,容器创建时,对象就被创建了。
对象或者:只要容器在,对象就一直活着。
对象死亡:当容器销毁时,对象就被销毁了。
多例对象:prototype
每次访问对象时,都会重新创建实例。
生命周期
对象出生:当使用对象时,容器创建新的实例。
对象或者:只要对象在使用中,就一直活着。
对象死亡:当对象长时间未被使用时,就会被java的GC垃圾回收器回收了。
实例化bean的四种方式
第一种,使用默认的无参构造
在默认情况下,会根据舞草构造来实例化对象。如果没有无参构造,则会创建失败。
<bean id="UserDao" class="com.xxxx.spring.dao.impl.UserDaoImpl"></bean>
第二种,使用静态工厂方法创建
/**
*模拟一个静态工厂,创建业务层实现类
*/
public class StaticFactory {
public static UserService createUserService(){
return new UserServiceImpl();
}
}
使用 StaticFactory 类中的静态方法 createUserService 创建对象,并存入 spring 容器
id 属性:指定 bean 的 id,用于从容器中获取
class 属性:指定静态工厂的全限定类名
factory-method 属性:指定生产对象的静态方法
<bean id="userService" class="com.xxxx.spring.factory.StaticFactory" factory-mathod="createUserService"></bean>
第三种方式,Spring管理实例工厂,使用实例工厂的方法创建对象
/**
*模拟一个示例工厂,创建业务层实现类
此工厂创建实例对象,必须先有工厂实例对象,再调用方法创建对象
*/
public class InstanceFactory {
public UserService createUserService(){
return new UserServiceImpl();
}
}
bean:
<bean id="instanceFactory" class="com.xxxx.spring.factory.InstanceFactory"/>
<bean id="userService"
factory-bean="instanceFactory"
factory-method="createUserService"></bean>
解释:先把工厂的创建交给 spring 来管理。然后再使用工厂的 bean 来调用里面的方法创建。
factory-bean 属性:用于指定实例工厂 bean 的 id。
factory-method 属性:用于指定实例工厂中创建对象的方法。
第四种方式,实现Spring的FactoryBean接口实例化
public class UserServiceInstance implements FactoryBean {
@Override
//获取对象的方法
public Object getObject() throws Exception {
return new UserServiceImpl();
}
@Override
//获取对象的类型的方法
public Class<?> getObjectType() {
return UserService.class;
}
}
bean:
<bean id="userService" class="com.woniuxy.spring.UserServiceInstance" />
依赖注入的三种方式
依赖注入: Dependency Injection。它是 spring 框架核心 ioc 的具体实现。 前面我们通过控制反转,把对象的创建交给了 spring,但是代码中不可能出现没有依赖的情况。 ioc 解耦只是降低他们的依赖关系,并不是消除。例如:我们的业务层仍会调用持久层的方法。 那这种业务层和持久层的依赖关系,在使用 spring 之后,就让 spring 来维护了。 简单的说,就是坐等框架把持久层对象传入业务层,而不用我们自己去获取
第一种,set方法注入
此种方式注入,类中必须有需注入成员变量的set方法。用到标签为 property。
用法示例:
<bean id="userService" class="com.woniuxy.spring.UserServiceInstance" >
<property name="userDao" ref="userDao"></property>
<property name="name" value="admin"></property>
<property name="age" value="21"></property>
</bean>
name: 找的是类中set方法后面的部分。
ref: 给类中成员赋值是其他bean类型的。
value: 给类中成员变量赋值是基本数据类型和String类型的。
List和Set类型的注入
<bean id="userService" class="com.woniuxy.spring.UserServiceInstance" >
<property name="jobs">
<list>
<value>秘书</value>
<value>经理</value>
<value>总监</value>
</list>
</property>
</bean>
Set类型相同,将标签换成标签即可。
Map类型的注入
使用标签,key和value为Map的key和value。
<property name="members">
<map>
<entry key="lidi" value="19"/>
<entry key="lisy" value="22"/>
<entry key="lucy" value="17"/>
<entry key="lily" value="24"/>
</map>
</property>
第二种,构造器注入
就是使用类中的构造函数(有参构造函数),给成员变量赋值。但是,赋值的操作不再由我们自己来做,而是通过配置的方式,让 spring 框架来为我们注入。
涉及标签:
constructor-arg
属性:
name 指定参数咋构造函数中的名称。用这个名称去找给谁赋值。
index 指定参数再构造函数参数列表中的索引位置,从0开始。
type 指定参数再构造函数中的数据类型
value 可以给基本数据类型和String类型赋值
ref 他能赋的值是其他bean类型(必须是再配置文件中配置过的bean)
示例:
<bean id="userService" class="com.woniuxy.spring.UserServiceInstance" >
<constructor-arg name="userDao" ref="userDao"></constructor-arg>
<constructor-arg name="userName" value="lisa"></constructor-arg>
<constructor-arg name="age" value="18"></constructor-arg>
<constructor-arg name="hobby" >
<list>
<value>读书</value>
<value>游泳</value>
<value>敲代码</value>
</list>
</constructor-arg>
</bean>
第三种方式,注解注入
此种方式会在后面注解配置方式中说明。
2.2.2.2 注解方式配置IOC
说明:此种方式仍然需要xml配置文件,需要再里面添加如下标签:
作用是告知Spring在创建容器时,要扫描的包。
<context:component-scan base-package="com.xxxxx.spring"/>
注解分类
- 用于创建对象的
- 用于注入数据的
- 用于改变作用范围的
- 和生命周期相关的
1.用于创建对象的
@Component:
作用:用于把当前类对象存入Spring容器中,属性 value 用于指定beande id ,当不写是,默认为当前类名,且首字母小写
@Service
@Controller
@Ropository
上面是Spring专为三层架构指定的注解,作用和@Component相同
2.用于注入数据的
@Autowired
作用:自动按照数据类型注入。只要容器中有唯一一个bean对象的数据集类型和要注入的变量的数据类型匹配,就可以注入成功。
出现位置:可以在变量上,也可以在方法上。
说明:使用注解方式注入时,set方法不是必须的。
如果IOC容器中没有任何bean的类型和要注入的变量类型匹配,则报错。如果有多个bean的类型和要注入的变量类型匹配,则看bean的id和要注入的变量名称是否相同,如果相同就注入,没有相同的,则报错。
@Qualifier
作用:再按照类型的基础上再按照变量名称注入。再给类成员注入时,必须要和@Autowired一起使用。再给方法注入时,可以单独使用。
属性:value 用于指定注入bean的id。
@Resource
作用:直接按bean的id注入,可以单独使用
属性:name,用于指定bean的id
说明:以上三种注入方式都只能注入其他bean类型的数据,而基本类型和String类型无法使用上述注解实现。另外,集合类型的注入只能通过xml配置来实现。
@Value
作用:用于注入基本类型和String类型的数据。
属性:value,用于指定数据的值。注解中的value="" value可以省略。直接写成@Value(“lisa”)。可以使用Spring的SPEL表达式。写法:${}
3.用于指定bean的作用范围
@Scope
属性: value,指定范围的取值,常用:Singleton(单例)和Prototype(多例)。
4.生命周期
@PostConstruct 用于i指定初始化方法
@PreDestroy 用于指定销毁方法
2.2.2.3 用Java代码方式配置IOC
注解: @Bean @Configuration @ComponentScan
- @Configuration 标记一个类为配置类
- @Bean 标记某个方法返回值为spring的bean,方法参数为依赖注入的请求
代码示例:
@Configuration
public class Config {
@Bean
public UserService userService(){
UserServiceImpl userService = new UserServiceImpl();
// 外部依赖注入
userService.setUserDao(userDao());
return userService;
}
@Bean
public UserDao userDao(){
//将QueryRunner对象注入UserDao
UserDaoImpl userDao = new UserDaoImpl();
// userDao.setQr(queryRunner());
return userDao;
}
@Bean
public UserController userController(){
UserController userController = new UserController();
//依赖注入,采用设置属性的方法
userController.setUserService(userService());
return userController;
}
}
2.2.2.4 用包扫描方式配置IOC
@Configuration 标记一个类为配置类 等价于配置文件: applicationContext.xml
@ComponentScan 打开包扫描功能,并且指定扫描的包 等价于 <context:component-scan base-package=“xxx”>
加入@Controller…@Autowired 等注解
如要配置数据库连接,需要引用配置文件可用下面方式引入:
@PropertySource("{配置文件位置}")
2.2.2.5 Java配置和注解混合使用
在注解类上可以用@Import导入Java配置,用ImportResource导入xml配置
@Import(AppConfig.class)
@ImportResource(“applicationContext.xml”)
3 AOP(Aspect Oritented Programming) 面向切面编程
3.1.1 什么是AOP
简单的说它就是把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的
基础上,对我们的已有方法进行增强。
3.1.2 AOP的作用和优势
作用:在程序运行期间,不修改源码,对已有方法进行增强
优势:减少重复代码,提高开发效率,方便维护
3.1.3 AOP的实现方式
使用动态代理技术
3.1.4 AOP的应用实例
打印日志、性能监控、事务管理、安全验证等等。
3.2.1 AOP的一些名词
- 连接点:JoinPoint,需要加入功能的位置,一般是方法。
- 切入点:Pointcut,真正执行加入功能的连接点。
- 通知:Advice,需要实现的功能。
- 切面:Aspect, Java语言中,将切入点和通知等组装在一起的代码单元。
- 目标对象:Target, 要操作的对象。
- 织入:Weave ,将功能加入到切入点中的过程。
通知类型:
- 前置通知 : 方法执行之前 MethodBeforeAdvice
- 后置通知 : 方法执行之后 AfterReturningAdvice
- 环绕通知 : 方法执行前后 MethodInterceptor
- 异常通知 : 抛出异常时
- 最终通知 : finally执行时
3.2.2 xml配置AOP的步骤
1) 编写service类
2) 编写通知 , 实现MethodBeforeAdvice接口
//method 要执行的方法
// args 方法的参数
// target 方法所在的对象
public void before(Method method, Object[] args, Object target) throws Throwable {
}
3)配置xml
- 配置service
- 配置通知
- 配置切入点,class= org.springframework.aop.support.JdkRegexpMethodPointcut ,配置属性pattern=> service的方法
- 配置切面,class=org.springframework.aop.support.DefaultPointcutAdvisor 连接切入点和通知
- 包装service类, class= org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator
- 获取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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--目标对象-->
<bean id="userService" class="com.woniuxy.spring.aop.service.impl.UserServiceImpl"/>
<!--通知: 实现了打日志的功能-->
<bean id="beforeExecution" class="com.woniuxy.spring.aop.component.BeforeExecution"/>
<!--切入点:选出了需要增加功能的方法-->
<bean id="pointCut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
<property name="pattern" value="com.woniuxy.spring.aop.service.impl.UserServiceImpl.addUser"/>
</bean>
<!--切面:连接切入点和通知,让打日志功能在切入点的位置执行-->
<bean id="aspect" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="pointcut" ref="pointCut"/>
<property name="advice" ref="beforeExecution"/>
</bean>
<!--包装userService-->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
</beans>
关于切面的配置
<aop:config>
<aop:aspect ref="txAdvice">
<!--切入点-->
<aop:pointcut id="servicePointcut" expression="execution(* com.woniuxy.spring.aop.service.impl.*.*(..))"/>
<!--通知-->
<!--前置--><aop:before method="begin" pointcut-ref="servicePointcut"/>
<!--后置--><aop:after-returning method="commit" pointcut-ref="servicePointcut"/>
<!--异常--><aop:after-throwing method="rollback" pointcut-ref="servicePointcut"/>
</aop:aspect>
</aop:config>
注解式配置AOP
@Aspect
@Pointcut
@Around @Befrore @After @AfterReturning @AfterThrowing
@EnableAspectJAutoProxy
代码示例:
/**
* 用另一种方式,用java代码代替xml配置文件,调用时对应App类中的第二种方法
*/
@Configuration
@ComponentScan("com.woniuxy.spring.aop")
@EnableAspectJAutoProxy
public class AopConfig {
}
@Component
@Aspect
public class TxAspect {
//配置切入点
@Pointcut("execution(* com.woniuxy.spring.aop.service.impl.*.*(..))")
public void servicePointcut(){}
@Around("servicePointcut()")//通知类型
public Object aroundAdvice(ProceedingJoinPoint pjp){
Object args[] = pjp.getArgs();
Object res = null;
try{
System.out.println("开启事务");
res = pjp.proceed(args);
System.out.println("提交事务");
} catch (Throwable throwable) {
throwable.printStackTrace();
System.out.println("回滚事务");
}
return res;
}
}