目录
【4】创建Spring的配置文件application.xml
1、什么是框架?
框架( Framework ):框(指其约束性)架(指其支撑性),在软件设计中指为解决一个开放性问题而设计的具有一定约束性的支撑结构。在此结构上可以根据具体问题扩展、安插更多的组成部分,从而更 迅速和方便地构建完整的解决问题的方案。如何学习框架呢?1 、知道框架能做什么2 、学习框架的语法,一般框架完成一个功能需要一定的步骤3 、框架的内部实现原理(扩展)4 、尝试实现一个框架(提升)
2、Spring是什么?
Spring 被称为 J2EE 的春天,是一个是分层的 Java SE/EE full-stack 开源 的 轻量级 的 Java 开发框架, 是最受欢迎的企业级 Java 应用程序开发框架,数以百万的来自世界各地的开发人员使用 Spring 框架来创建性能好、易于测试、可重用的代码。Spring 具有 控制反转 ( IoC )和 面向切面 ( AOP )两大核心。 Java Spring 框架通过声明式方式灵活地进行 事务的管理 ,提高开发效率和质量。
3、Spring的优势?
1 、方便解耦,简化开发Spring 就是一个大工厂,可以将所有对象的创建和依赖关系的维护交给 Spring 管理。2 、方便集成各种优秀框架Spring 不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如 Struts2 、 Hibernate 、MyBatis 等)的直接支持。3 、降低 Java EE API 的使用难度Spring 对 Java EE 开发中非常难用的一些 API ( JDBC 、 JavaMail 、远程调用等)都提供了封装,使这些 API 应用的难度大大降低。4 、方便程序的测试Spring 支持 JUnit4 ,可以通过注解方便地测试 Spring 程序。5 、 AOP 编程的支持Spring 提供面向切面编程,可以方便地实现对程序进行权限拦截和运行监控等功能。6 、声明式事务的支持只需要通过配置就可以完成对事务的管理,而无须手动编程。
4、创建Hello World项目(两种方式)
4.1、官网创建
4.2、本地创建(IDEA)
【1】创建maven工程
【2】 完成后
5、Spring核心之IoC控制反转
Ioc—Inversion of Control ,即 “ 控制反转 ” ,不是什么技术,而是一种设计思想。IoC 是指在程序开发中,实例的创建不再由调用者管理,而是由 Spring 容器创建。 Spring 容器会负责控制程序之间的关系,而不是由程序代码直接控制,因此,控制权由程序代码转移到了 Spring 容器中,控 制权发生了反转,这就是 Spring 的 IoC 思想。
【1】创建一个实体类
public class Team {
private Integer id;
private String name;
private String location;
public Team() {
System.out.println("Tesm-->默认构造方法 id="+id+",name="+name+",location="+location);
}
}
【2】创建一个测试类,以前
现在:
@Test
public void test01(){
//Team team = new Team();以前的
//使用spring容器创建对象
String springConfig="application.xml";
//2--->BeanFactory beanFactory =new XmlBeanFactory(new )
//3-->
ApplicationContext appletContext = new ClassPathXmlApplicationContext(springConfig);
//4-->applicationContext.getBean
Team team1= (Team) appletContext.getBean("team1");
}
【3】添加依赖
<!--
junit:代表测试@test注解
-->
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.12</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
</plugin>
</plugins>
</build>
【4】创建Spring的配置文件application.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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
创建对象:
声明bean,通知spring要创建哪个类的对象
一个bean标签声明一个对象:
id="自定义的对象名称" ,
要求唯一 class="类的完全限定名" 包名+类名
spring底层是反射机制创建对象,所以必须使用类名
相当于 Team team1=new Team();
创建好的对象放入一个集合Map中
例如:springMap.put("team1",new Team()); -->
<bean id="team1" class="com.qinluyu.pojo.Team"></bean>
</beans>
【5】创建非自定义对象(获取时间)
Date date1 = (Date) applicationContext.getBean("date1");
System.out.println("自定义对象调用"+date1);
<bean id="date1" class="java.util.Date"></bean>
6、Spring容器创建对象的方式
【1】使用默认的构造方法
public Team() {
System.out.println("Team-->默认构造方法 id="+id+",name="+name+",location="+location);
}
<bean id="team1" class="com.qinluyu.pojo.Team"></bean>
【2】使用带参数的构造方法
public Team(Integer id, String name, String location) {
this.id = id;
this.name = name;
this.location = location;
System.out.println("Team-->带参数构造方法 id="+id+",name="+name+",location="+location);
}
@Test
public void test02(){
String springConfig="application.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(springConfig);
}
【3】使用工厂类
<!--通过工厂方法:实例方法,静态方法 1、静态方法-->
<bean id="staticTeam" class="com.qinluyu.pojo.MyFactory" factory-method="staticFun"></bean>
<!--实例方法-->
<bean id="factory" class="com.qinluyu.pojo.MyFactory"></bean>
<bean id="instanceTeam" factory-bean="factory" factory-method="instanceFun"></bean>
//实例方法
public Team instanceFun(){
return new Team(1002,"李四","李四组");
}
//静态方法
public static Team staticFun(){
return new Team(1003,"李四1","李四组1");
}
public static void main(String[] args) {
MyFactory factory=new MyFactory();
Team team = factory.instanceFun();
Team team1 = MyFactory.staticFun();
}
@Test
public void test03(){
String springConfig="application.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(springConfig);
}
7、基于XML的DI
DI—Dependency Injection ,即 “ 依赖注入 ” :是组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并非为软件系统带来更多功能,而是为 了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。通过依赖注入机制,我们只需要通过 简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资 源来自何处,由谁实现。IoC 是一个概念,是一种思想,其实现方式多种多样。依赖注入就是其中用的比较多的一种方式。Ioc 和 DI 是同一个概念的不同角度描述 。 IoC 是一种思想,概念, DI 是实现它的手段。 Spring 框架使用依 赖注入实现 IoC
8、基于注解实现IoC
【1】声明Bean的注解 @Component
//@Component 不指定 value 属性,bean 的 id 是类名的首字母小写。
@Component
//@Component("teamDao")
//=@Component(value = "teamDao")
//=<bean id="teaDao" class="com.qinluyu.pojo.TeamDao"></bean>
【2】例子
实体
public TeamDao(){
System.out.println("TeamDao-----------默认的构造方法");
}
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: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/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.qinluyu.pojo"></context:component-scan>
</beans>
测试:
public void test03(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("annotation.xml");
}
【3】其他
除此之外, Spring 中还提供了其他 3 个用于创建对象的注解:@Repository : 用于 dao 实现类的的注解@Service: 用户 service 实现类的注解@Controller: 用于 controller 实现类的注解这三个注解与 @Component 都可以创建对象,但这三个注解还有其他的含义, @Service 创建业务层对象,业务层对象可以加入事务功能, @Controller 注解创建的对象可以作为处理器接收用户的请求。@Repository ,@Service ,@Controller是对 @Component 注解的细化,标注不同层的对象。即持久 层对象,业务层对象,控制层对象。代码相似,就不进行粘贴了
【4】包扫描
需要在 Spring 配置文件中配置组件扫描器,用于在指定的基本包中扫描注解。如果没有报扫描,添加的创建对象的注解不生效分隔符可以使用逗号(,)分号(;)还可以使用空格,不建议使用空格。base-package 是指定到父包名 (com.qinluyu)
<context:component-scan base-package="com.qinluyu.pojo"></context:component-scan>
【5】属性注入@Vaule
属性上使用注解 @Value ,该注解的 value 属性用于指定要注入的值。使用该注解完成属性注入时,类中无需 setter 。当然,若属性有 setter ,则也可将其加到 setter 上。
实体
@Component
public class Team {
@Value("1004")
private Integer id;
@Value("王五")
private String name;
@Value("王五1")
private String location;
@Override
public String toString() {
return "Team{" +
"id=" + id +
", name='" + name + '\'' +
", location='" + location + '\'' +
'}';
}
或者
public Integer getId() {
return id;
}
@Value("1004")
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
@Value("王五")
public void setName(String name) {
this.name = name;
}
public String getLocation() {
return location;
}
@Value("王五1")
public void setLocation(String location) {
this.location = location;
}
测试
@Test
public void test04(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("annotation.xml");
Team team = (Team) applicationContext.getBean("team");
System.out.println(team);
}
【6】@Autowired
需要在引用属性上使用注解 @Autowired ,该注解默认使用按类型自动装配 Bean 的方式。使用该注解完成属性注入时,类中无需 setter 。当然,若属性有 setter ,则也可将其加到 setter 上。
【7】@Autowired和@Qualifier
需要在引用属性上联合使用注解 @Autowired 与 @Qualifier 。 @Qualifier 的 value 属性用于指定要匹配的 Bean 的 id 值。类中无需 set 方法,也可加到 set 方法上。@Autowired 还有一个属性 required ,默认值为 true,表示当匹配失败后,会终止程序运行。若将其值设置为 false,则匹配失败,将被忽略,未匹配的属性值为 null。
【8】@Resource
@Resource 注解既可以按名称匹配 Bean ,也可以按类型匹配 Bean 。默认是按名称注入 。@Resource 可在属性 上,也可在 set 方法上
9、Spring核心之AOP
【1】什么是AOP?
AOP 为 Aspect Oriented Programming 的缩写,意思为 面向切面编程 ,是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP 的作用:不修改源码的情况下,程序运行期间对方法进行功能增强
【2】什么是代理模式?
代理模式:在一个原有功能的基础上添加新的功能。分类:静态代理和动态代理。
【3】静态代理
基于类的静态代理
/**
* 基于类的静态代理,每次只能代理一个类
*/
public class staticproxy extends TeamService{
public void add(){
try {
System.out.println("开始事务");
super.add();
System.out.println("提交事务");
} catch (Exception e) {
System.out.println("回滚事务");
}
}
}
基于接口的静态代理
接口
public interface IService {
void add();
}
package com.qinluyu;
public class ProxyLogService implements IService{
private IService service;//被代理的对象
public ProxyLogService(IService service) {
this.service = service;
}
@Override
public void add() {
try {
System.out.println("开始日志");
service.add();
System.out.println("提交日志");
} catch (Exception exception) {
System.out.println("回滚日志");
}
}
}
public class TeamService implements IService{
@Override
public void add(){
System.out.println("TeamService---- add----");// 核心业务
}
}
静态代理:要求代理类一定存在
【4】动态代理
动态代理:程序运行的时候,根据要被代理的对象动态生成代理类。类型:1 、基于 JDK 的动态代理2 、基于 CGLIB 的动态代理
【5】基于JDK的动态代理
package com.qinluyu;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class MyJDKProxy {
public static void main(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("回滚事务");
e.printStackTrace();
throw e;
} finally {
System.out.println("----");
}
}
}
);
//代理对象干活
proxyService.add();
System.out.println(teamService.getClass());
System.out.println(proxyService.getClass()+"--------");
}
}
【6】基于CGLIB的动态代理
public static void main(String[] args) {
//目标对象:没有接口
NBAService nbaService=new NBAService();
//创建切面
AOP tranAop=new TranAOP();
//创建代理对象:选择cglib动态代理
NBAService proxyInstance = (NBAService) new CglibProxyFactory().getProxyInstance(nbaService, tranAop);
int res=proxyInstance.add("huren",1001);
System.out.println(res);
}
public static void main1(String[] args) {
//目标对象:没有接口
NBAService nbaService=new NBAService();
//创建代理对象:选择cglib动态代理
NBAService proxyService= (NBAService) Enhancer.create(nbaService.getClass(),
new MethodInterceptor() {//回调函数编写代理规则
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
try {
System.out.println("开始事务");
Object invoke = methodProxy.invokeSuper(o, objects);//核心
System.out.println("提交事务");
return invoke;
}catch (Exception e){
System.out.println("事务回滚");
throw e;
}finally {
System.out.println("finally------------");
}
}
});
int res=proxyService.add("huren",1001);
System.out.println(res);
}
10、SpringAOP
Spring 的 AOP 实现底层就是对上面的动态代理的代码进行了封装,封装后我们只需要对需要关注的部分进行代码编写,并通过配置的方式完成指定目标的方法增强。
【1】AspectJ 对 AOP 的实现
在 Spring 中使用 AOP 开发时,一般使用 AspectJ 的实现方式AspectJ 是一个优秀面向切面的框架,它扩展了 Java 语言,提供了强大的切面实现。
【2】AspectJ的通知类型
1. 前置通知2. 后置通知3. 环绕通知4. 异常通知5. 最终通知
【3】注解方式实现AOP
开发阶段:关注核心业务和 AOP 代码
TeamService
@Service
public class TeamService implements IService{
@Override
public void add(int id, String name) {
//int num=10/0;
System.out.println("TeamService---- add----");
}
@Override
public boolean update(int num) {
System.out.println("TeamService---- update----");
if(num>666){
return true;
}
return false;
}
IService:
public interface IService {
void add(int id,String name);
boolean update(int num);
}
【4】前置通知
@Before("pointCut()")
public void before(JoinPoint jp){
System.out.println("前置通知:在目标方法执行之前被调用的通知");
String name = jp.getSignature().getName();
System.out.println("拦截的方法名称:"+name);
Object[] args = jp.getArgs();
System.out.println("方法的参数格式:"+args.length);
System.out.println("方法参数列表:");
for (Object arg : args) {
System.out.println("\t"+arg);
}
}
【5】后置通知
@AfterReturning(value = "pointCut2()",returning = "result")
public Object afterReturn(Object result){
if(result!=null){
boolean res=(boolean)result;
if(res){
result=false;
}
}
System.out.println("后置通知:在目标方法执行之后被调用的通知,result="+result);
return result;
}
【6】环绕通知
@Around(value = "pointCut()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("环绕方法---目标方法的执行之前");
Object proceed = pjp.proceed();
System.out.println("环绕方法---目标方法的执行之后");
return proceed;
}
【7】最终通知
@After( "pointCut()")
public void myFinally(){
System.out.println("最终通知:无论是否出现异常都是最后被调用的通知");
}
【8】异常通知
@AfterThrowing(value = "pointCut()",throwing = "ex")
public void exception(JoinPoint jp,Throwable ex){
//一般会把异常发生的时间、位置、原有都记录下来
System.out.println("异常通知:在目标方法执行出现异常的时候才会别调用的通知,否则不执行");
System.out.println(jp.getSignature()+"方法出现异常,异常信息是:"+ex.getMessage());
}
【9】XML方式实现AOP
/**
* 切面类
*/
@Component //切面对象的创建权限依然交给spring容器
@Aspect //aspectj 框架的注解 标识当前类是一个切面类
public class MyAOP {
public void before(JoinPoint jp){
System.out.println("AOP前置通知:在目标方法执行之前被调用的通知");
}
public void afterReturn(Object result){
System.out.println("AOP后置通知:在目标方法执行之后被调用的通知,result="+result);
}
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("AOP环绕方法---目标方法的执行之前");
Object proceed = pjp.proceed();
System.out.println("AOP环绕方法---目标方法的执行之后");
return proceed;
}
public void exception(JoinPoint jp,Throwable ex){
//一般会把异常发生的时间、位置、原有都记录下来
System.out.println("AOP异常通知:在目标方法执行出现异常的时候才会别调用的通知,否则不执行");
System.out.println(jp.getSignature()+"方法出现异常,异常信息是:"+ex.getMessage());
}
public void myFinally(){
System.out.println("AOP最终通知:无论是否出现异常都是最后被调用的通知");
}
}
<!--xml方式实现AOP-->
<aop:config>
<aop:pointcut id="pt1" expression="execution(* com.qinluyu.service..*.*(..))"/>
<aop:pointcut id="pt2" expression="execution(* com.qinluyu.service..*.add*(..))"/>
<aop:aspect ref="myAOP">
<!--前置通知-->
<aop:before method="before" pointcut-ref="pt1"></aop:before>
<!--后置通知-->
<aop:after-returning method="afterReturn" pointcut-ref="pt2" returning="result"></aop:after-returning>
<!--环绕通知-->
<aop:around method="around" pointcut-ref="pt2"></aop:around>
<!--异常通知-->
<aop:after-throwing method="exception" pointcut-ref="pt1" throwing="ex"></aop:after-throwing>
<!--最终通知-->
<aop:after method="myFinally" pointcut-ref="pt1"></aop:after>
</aop:aspect>
</aop:config>
11、Spring整合JDBC
依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>spring02</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.12</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.5</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.45</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
测试
package com.qinluyu.test;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.junit.Test;
import org.springframework.jdbc.core.JdbcTemplate;
public class Test01 {
@Test
public void test01() throws Exception{
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&characterEncoding=utf8&useUnicode=true&useSSL=false");
dataSource.setUser("root");
dataSource.setPassword("123");
//使用JDBCTemplete
JdbcTemplate template = new JdbcTemplate(dataSource);
String sql = "insert into team(teamName,location) value(?,?)";
int update = template.update(sql,"zhangsan","123");
System.out.println("数据"+update);
}
}
12、Spring事务管理
事务原本是数据库中的概念,在 Dao 层。但在实际开发中,一般将事务提升到业务层,即 Service 层。
【1】事务管理器接口
PlatformTransactionManager 接口常用的实现类 :DataSourceTransactionManager :使用 JDBC 或 MyBatis 进行数据库操作时使用。Spring 事务的默认回滚方式是:发生运行时异常和 error 时回滚,发生受查 ( 编译 ) 异常时提交。不过,对于受查异常,程序员也可以手工设置其回滚方式。
【2】事务隔离级别常量
这些常量均是以 ISOLATION_ 开头。即形如 ISOLATION_XXX 。➢ DEFAULT :采用 DB 默认的事务隔离级别。 MySql 的默认为 REPEATABLE_READ ; Oracle 默认为READ_COMMITTED 。➢ READ_UNCOMMITTED :读未提交。未解决任何并发问题。➢ READ_COMMITTED :读已提交。解决脏读,存在不可重复读与幻读。➢ REPEATABLE_READ :可重复读。解决脏读、不可重复读,存在幻读➢ SERIALIZABLE :串行化。不存在并发问题。