可能比较快,这只是我一个学习的笔记
什么是Spring?
javaSE/EE full-stack 轻量级开源框架 、以IoC 和 AOP为内核、使用基本的javaBean来完成EJB晚餐的工作
开发中的体系
实际开发钟使用三层体系架构 :表示层、业务逻辑层、持久层(DAO数据库层)
Spring框架特点:
1.非入侵式设计
2.方便解耦、简化开发
3.支持AOP
4.支持声明式事务处理
5.方便程序测试
6.方便集成各种优秀框架
Spring的核心容器
Spring会控制程序之间的关系,并不是由Spring直接控制。
Spring核心容器BeanFactory和ApplicationContext
ApplicationContext比较常用 通常两种配置方法如下:
1.
// 定义配置文件路径
String xmlPath = "com/itheima/annotation/beans6.xml";
// 加载配置文件
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext(xmlPath);
依赖注入与控制反转
DI全称依赖注入与IoC(控制反转)的含义相同,两个角度描述同一个概念
DI | Sping 容器负责将被依赖对象赋值调用者的成员变量,相当于注入实例,这就是依赖注入 |
---|---|
IoC | 使用Spring框架后。对象不再有调用者来创建、是Spring容器创建、容器会负责控制程序之间的关系 |
Spring中的bean
Bean :零件 、java类对象
Bean的配置 :properties(文件)、XML(id、name),通常是使用XML的方式
Bean的实例化:构造器的实例化、静态工厂实例化、实例工厂实例化,这里介绍常用的构造器实例化
java类bean1里面什么都没有
package com.itheima.instance.constructor;
import org.springframework.context.ApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
public class InstanceTest1 {
public static void main(String[] args) {
// 定义配置文件路径
String xmlPath = "com/itheima/instance/constructor/beans1.xml";
// ApplicationContext在加载配置文件时,对Bean进行实例化
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext(xmlPath);
Bean1 bean = (Bean1) applicationContext.getBean("bean1");
System.out.println(bean);
}
}
bean1在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-4.3.xsd">
<bean id="bean1" class="com.itheima.instance.constructor.Bean1" />
</beans>
控制台输出:bean1的地址
五月 18, 2020 11:56:13 上午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@1a6c5a9e: startup date [Mon May 18 11:56:13 CST 2020]; root of context hierarchy
五月 18, 2020 11:56:13 上午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [com/itheima/instance/constructor/beans1.xml]
com.itheima.instance.constructor.Bean1@737996a0
bean的作用域
bean的装配方式:
1.XML:
a.设值注入 <property name="usename" value="张三"></property>
b.构造注入<ocnstructor-arg index="0" value="tom"//index 参数位置,从0开始
缺点:工作复杂
2.Annotation(注释):
@component:描述Spring中的Bean
@Repository:DAO(数据访问层) Spring中的Bean
@Service: 业务层的类标识
@Controller: 控制层的类标识(页面管理)
@Autowired: Bean的属性变量 (属性、构造)注入
@Resource: 与 @Autowired 功能一样
@Qualifier :区分同名
类扫描:<context : component-scan base-package="包名"/> //自动扫描包内的Bean
<context:component-scan base-package="com.itheima.annotation" />
3.自动装配:设置autowire属性值来实现自动装配 配置到其他的<bean>内实现自动:
<bean id="userDao"
class="com.itheima.annotation.UserDaoImpl" />
<bean id="userService"
class="com.itheima.annotation.UserServiceImpl" autowire="byName" />
///chapter02/src/com/itheima/assemble/XmlBeanAssembleTest.java
Spring中的AOP
AOP :面向切面编程,是面向对象编程(OOP)的补充
动态代理:
JDK的动态代理:代理对象有一个或者多个接口
入口是Proxy,Proxy有个静态的方法 getProxyClass(class,interfaces)传入类加载器和一组接口,它会给你返回Class对象。创建出一个·实例关键就是得到得到对应的Class对象,new出对象直接返回的是对象。
能否不写代理类,而直接得到代理Class对象,然后根据它创建代理实例(反射)?Class对象包含了一个类的所有信息:构造器、方法—>不写代理类从和获取类信息—>代理类和目标类理应实现同一组接口《之所以同一组接口,为了尽可能的保证代理对象内部结构和目标对象一致,这样我们对代理对象的操作最终都可以转移到目标对象的身上,代理对象可以专注于增强代码的编写,后续多的需求不用使用底层源代码,代理对象处理后多的需求》
Proxy.getProxyClass()这个方法的本质就是:以Class造Class
代理Class的构造器船创建对象,需要传入InvocationHandler,每次调用代理对象的方法最终都会调用InvocationHandler的invoke();
动态代理的对象必须实现一个或者多个接口,为此CGLIB刚刚好解决了这个问题
CGLIB:无接口 、拦截器 CglibProxy implements MethodInterceptor// 实现接口
基于代理的AOP实现
本地代码com.itheima.factorybean类
** AspectJ开发**
1.基于XML的声明式AspectJ,所有切面、切入点和通知都必须定义在aop:config>元素内
2.基于注解AspectJ的开发
xml:
1.定义配置切面aop:aspect id:标识符 ref:全类
2.定义配置切点<aop: pointcut> id:标识符 expression :表达式<aop:pointcut id=“myPointCut”
expression=“execution(* com.itheima.jdk..(…))”
3.配置通知 aop:aspect的子元素配置通知
MyAspect
package com.itheima.aspectj.xml;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
/**
*切面类,在此类中编写通知
*/
public class MyAspect {
// 前置通知
public void myBefore(JoinPoint joinPoint) {
System.out.print("前置通知 :模拟执行权限检查...,");
System.out.print("目标类是:"+joinPoint.getTarget() );
System.out.println(",被织入增强处理的目标方法为:"
+joinPoint.getSignature().getName());
}
// 后置通知
public void myAfterReturning(JoinPoint joinPoint) {
System.out.print("后置通知:模拟记录日志...," );
System.out.println("被织入增强处理的目标方法为:"
+ joinPoint.getSignature().getName());
}
/**
* 环绕通知
* ProceedingJoinPoint 是JoinPoint子接口,表示可以执行目标方法
* 1.必须是Object类型的返回值
* 2.必须接收一个参数,类型为ProceedingJoinPoint
* 3.必须throws Throwable
*/
public Object myAround(ProceedingJoinPoint proceedingJoinPoint)
throws Throwable {
// 开始
System.out.println("环绕开始:执行目标方法之前,模拟开启事务...");
// 执行当前目标方法
Object obj = proceedingJoinPoint.proceed();
// 结束
System.out.println("环绕结束:执行目标方法之后,模拟关闭事务...");
return obj;
}
// 异常通知
public void myAfterThrowing(JoinPoint joinPoint, Throwable e) {
System.out.println("异常通知:" + "出错了" + e.getMessage());
}
// 最终通知
public void myAfter() {
System.out.println("最终通知:模拟方法结束后的释放资源...");
}
}
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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<!-- 1 目标类 -->
<bean id="userDao" class="com.itheima.jdk.UserDaoImpl" />
<!-- 2 切面 -->
<bean id="myAspect" class="com.itheima.aspectj.xml.MyAspect" />
<!-- 3 aop编程 -->
<aop:config>
<!-- 配置切面 -->
<aop:aspect ref="myAspect">
<!-- 3.1 配置切入点,通知最后增强哪些方法 -->
<aop:pointcut id="myPointCut"
expression="execution(* com.itheima.jdk.*.*(..))"
/>
<!-- 3.2 关联通知Advice和切入点pointCut -->
<!-- 3.2.1 前置通知 -->
<aop:before method="myBefore" pointcut-ref="myPointCut" />
<!-- 3.2.2 后置通知,在方法返回之后执行,就可以获得返回值
returning属性:用于设置后置通知的第二个参数的名称,类型是Object -->
<aop:after-returning method="myAfterReturning"
pointcut-ref="myPointCut" returning="returnVal" />
<!-- 3.2.3 环绕通知 -->
<aop:around method="myAround" pointcut-ref="myPointCut" />
<!-- 3.2.4 抛出通知:用于处理程序发生异常-->
<!-- * 注意:如果程序没有异常,将不会执行增强 -->
<!-- * throwing属性:用于设置通知第二个参数的名称,类型Throwable -->
<aop:after-throwing method="myAfterThrowing"
pointcut-ref="myPointCut" throwing="e" />
<!-- 3.2.5 最终通知:无论程序发生任何事情,都将执行 -->
<aop:after method="myAfter" pointcut-ref="myPointCut" />
</aop:aspect>
</aop:config>
</beans>
测试类
package com.itheima.aspectj.xml;
import org.springframework.context.ApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
import com.itheima.jdk.UserDao;
// 测试类
public class TestXmlAspectj {
public static void main(String args[]) {
String xmlPath =
"com/itheima/aspectj/xml/applicationContext.xml";
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext(xmlPath);
// 1 从spring容器获得内容
UserDao userDao = (UserDao) applicationContext.getBean("userDao");
// 2 执行方法
userDao.addUser();
userDao.deleteUser();
}
}
///chapter03/src/com/itheima/aspectj/xml/TestXmlAspectj.java
控制台结果
Spring的事务管理
三个核心接口
1.PlatformTransactionManager接口:代表事务管理接口,不知道底层
a.getTransation 获取事务状态
b.commit 提交事务
c.rollback 回滚事务
2.TransactionDefinition接口:事务描述对象,定义事务规则
a.getName 获取事务对象名称
b.getlsolationLevel 获取事务的隔离级别
c.getPropagationBehavior 获取事务的传播行为
d.getTimeout 获取队伍的超时时间
e.isReadOnly 是否事务只读
3.TransactionStaus接口:事务状态
a.flush 刷新事务 (写入数据)
b.hasSavepion() 获取事务是否存在保存点
c.isCompleted() 获取事务是否完成
d.isNewTeansaction() 获取是否为新事物
e.isRollbackOnuly() 获取事务是否回滚
f.setRollbackOnly() 设置事务是否回滚
管理的实现
1.XML的方式的声明事务(理解)
a.配置<tx:advice>中重点配置的<tx:method>
2.Annotation的方式(掌握,非常熟悉):
<bean id="transactionManager" class=
"org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 5.注册事务管理器驱动 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
//注意这里的扫描不是chapter05的,是chapter10的
//这里没有是因为已经配置了实体的Bean
<!-- 开启扫描 -->
<context:component-scan base-package="com.itheima.service" />
//chapter05
在对应的需要事务的方法前加上 @Transactional
Spring数据库开发
直接上实例:
- 配置一个
applicationContext.xml环境
<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-4.3.xsd">
<!-- 1配置数据源 -->
<bean id="dataSource" class=
"org.springframework.jdbc.datasource.DriverManagerDataSource">
<!--数据库驱动 -->
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
<!--连接数据库的url -->
<property name="url" value="jdbc:mysql://localhost:3306/spring?characterEncoding=utf8&useUnicode=true&useSSL=false&serverTimezone=UTC" />
<!--连接数据库的用户名 -->
<property name="username" value="root" />
<!--连接数据库的密码 -->
<property name="password" value="123456" />
</bean>
<!-- 2配置JDBC模板 -->
<bean id="jdbcTemplate"
class="org.springframework.jdbc.core.JdbcTemplate">
<!-- 默认必须使用数据源 -->
<property name="dataSource" ref="dataSource" />
</bean>
<!--定义id为accountDao的Bean-->
<bean id="accountDao" class="com.itheima.jdbc.AccountDaoImpl">
<!-- 将jdbcTemplate注入到accountDao实例中 -->
<property name="jdbcTemplate" ref="jdbcTemplate" />
</bean>
</beans>
- AccountDao接口的方法实现
package com.itheima.jdbc;
import java.util.List;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
public class AccountDaoImpl implements AccountDao {
// 声明JdbcTemplate属性及其setter方法
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
// 添加账户
public int addAccount(Account account) {
// 定义SQL
String sql = "insert into account(username,balance) value(?,?)";
// 定义数组来存放SQL语句中的参数
Object[] obj = new Object[] {
account.getUsername(),
account.getBalance()
};
// 执行添加操作,返回的是受SQL语句影响的记录条数
int num = this.jdbcTemplate.update(sql, obj);
return num;
}
// 更新账户
public int updateAccount(Account account) {
// 定义SQL
String sql = "update account set username=?,balance=? where id = ?";
// 定义数组来存放SQL语句中的参数
Object[] params = new Object[] {
account.getUsername(),
account.getBalance(),
account.getId()
};
// 执行添加操作,返回的是受SQL语句影响的记录条数
int num = this.jdbcTemplate.update(sql, params);
return num;
}
// 删除账户
public int deleteAccount(int id) {
// 定义SQL
String sql = "delete from account where id = ? ";
// 执行添加操作,返回的是受SQL语句影响的记录条数
int num = this.jdbcTemplate.update(sql, id);
return num;
}
// 通过id查询账户数据信息
public Account findAccountById(int id) {
//定义SQL语句
String sql = "select * from account where id = ?";
// 创建一个新的BeanPropertyRowMapper对象
RowMapper<Account> rowMapper =
new BeanPropertyRowMapper<Account>(Account.class);
// 将id绑定到SQL语句中,并通过RowMapper返回一个Object类型的单行记录
return this.jdbcTemplate.queryForObject(sql, rowMapper, id);
}
// 查询所有账户信息
public List<Account> findAllAccount() {
// 定义SQL语句
String sql = "select * from account";
// 创建一个新的BeanPropertyRowMapper对象
RowMapper<Account> rowMapper =
new BeanPropertyRowMapper<Account>(Account.class);
// 执行静态的SQL查询,并通过RowMapper返回结果
return this.jdbcTemplate.query(sql, rowMapper);
}
}
- Account账户类和接口
public class Account {
private Integer id; // 账户id
private String username; // 用户名
private Double balance; // 账户余额
public Integer getId() {
return id;
}//下面使它的set和get方法这里就不重复了
//下面是Account接口类的空方法
public interface AccountDao {
// 添加
public int addAccount(Account account);
// 更新
public int updateAccount(Account account);
// 删除
public int deleteAccount(int id);
// 通过id查询
public Account findAccountById(int id);
// 查询所有账户
public List<Account> findAllAccount();
}
- 测试类:
public class JdbcTemplateTest {
/**
* 使用execute()方法建表
// */
@Test
public void mainTest() {
// 加载配置文件
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取JdbcTemplate实例
JdbcTemplate jdTemplate =
(JdbcTemplate) applicationContext.getBean("jdbcTemplate");
// 使用execute()方法执行SQL语句,创建用户账户管理表account
jdTemplate.execute("create table account(" +
"id int primary key auto_increment," +
"username varchar(50)," +
"balance double)");
System.out.println("账户表account创建成功!");
}
@Test
public void addAccountTest() {
// 加载配置文件
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取AccountDao实例
AccountDao accountDao =
(AccountDao) applicationContext.getBean("accountDao");
// 创建Account对象,并向Account对象中添加数据
Account account = new Account();
account.setUsername("Rose");
account.setBalance(1000.00);
// 执行addAccount()方法,并获取返回结果
int num = accountDao.addAccount(account);
if (num > 0) {
System.out.println("成功插入了" + num + "条数据!");
} else {
System.out.println("插入操作执行失败!");
}
}
@Test
public void updateAccountTest() {
// 加载配置文件
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取AccountDao实例
AccountDao accountDao =
(AccountDao) applicationContext.getBean("accountDao");
// 创建Account对象,并向Account对象中添加数据
Account account = new Account();
account.setId(1);
account.setUsername("tom");
account.setBalance(2000.00);
// 执行updateAccount()方法,并获取返回结果
int num = accountDao.updateAccount(account);
if (num > 0) {
System.out.println("成功修改了" + num + "条数据!");
} else {
System.out.println("修改操作执行失败!");
}
}
@Test
public void deleteAccountTest() {
// 加载配置文件
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取AccountDao实例
AccountDao accountDao =
(AccountDao) applicationContext.getBean("accountDao");
// 执行deleteAccount()方法,并获取返回结果
int num = accountDao.deleteAccount(1);
if (num > 0) {
System.out.println("成功删除了" + num + "条数据!");
} else {
System.out.println("删除操作执行失败!");
}
}
@Test
public void findAccountByIdTest() {
// 加载配置文件
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取AccountDao实例
AccountDao accountDao =
(AccountDao) applicationContext.getBean("accountDao");
// 执行findAccountById()方法
Account account = accountDao.findAccountById(1);
System.out.println(account);
}
@Test
public void findAllAccountTest() {
// 加载配置文件
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取AccountDao实例
AccountDao accountDao =
(AccountDao) applicationContext.getBean("accountDao");
// 执行findAllAccount()方法,获取Account对象的集合
List<Account> account = accountDao.findAllAccount();
// 循环输出集合中的对象
for (Account act : account) {
System.out.println(act);
}
}
}
//chapter04
结果就不演示了,