1.spring是一个项目管理框架,同时也是一套Java EE解决方案
2.Spring是众多优秀设计模式的组合(工厂、单例、代理、适配器、包装器、观察者、模板、策略)
3.Spring并未替代现有框架产品,而是将众多框架进行有机整合,简化企业级开发,俗称"胶水框架"
解决的问题:service调用dao,原来的做法是自己new对象,当需要更改dao层的实现,只能更改编码. 从而实现对象间的解耦
主要类:MyClassPathXmlApplicaionContext
1.解析配置文件:把解析的信息封装到BeanDefinition.
得到bean的信息,把bean的信息封装到BeanDefinition,每个bean都会有自己的beanDefinition,把很多bean的beanDefinition放入一个map中.
2.通过反射创建对象:把对象放入对象池map中,此时放的是未给属性赋值的对象
从beansMap中获取bean的信息通过反射创建对象,将创建出来的对象放入objectMap
3.属性注入:通过反射调用对象的set方法,给对象的属性赋值
di:依赖注入,第二步创建的对象的属性时没有值的
IOC容器基本实现,时Spring内部的使用接口,不提供开发人员上进行使用.
加载配置文件时后不会创建对象,再获取对象(使用)才去创建对象.
public interface BeanFactory { }
:BeanFactory接口的子接口,提供更多更强大的功能,一般有开发人员进行使用.
加载配置文件时候就会把在配置文件对象进行创建.
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory,HierarchicalBeanFactory,MessageSource,ApplicationEventPublisher, ResourcePatternResolver { }
- ClassPathXmlApplicationContext:以xml的形式告诉容器管理那些bean
public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext { }
//创建spring 容器,通过配置文件 beans1.xml 告知容器 要管理的 bean 有哪些 ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans1.xml");
- AnnotationConfigApplicationContext:以注解的形式告诉容器管理那些bean
public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry { }
//加载配置类 ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
反转了依赖关系的满足方式,由之前的自己创建依赖对象,变成由工厂推送.(便主动为被动,即反转),解决了具有以来关系的组件之间的强耦合,使得项目形态更加稳健.
(1)IOC的概念:Inverse Of Controll:控制反转
控制反转,把对象创建和对象之间的调用过程,交给spring进行管理
(2)IOC的作用:为了降低耦合度
(3)IOC的底层实现:xml解析、工厂模式、反射
概念:在Spring创建对象的同时,为其属性赋值,称之为依赖注入
(1) set注入:创建对象时,spring工厂会通过Set方法为对象的属性赋值. bean中属性:
(2) 构造注入:bean中属性:
也叫自动装配.根据装配规则(属性名和属性类型)spring自动将装配的属性值进行注入
- byName:根据属性名称注入,注入值得bean的id和类的属性名一样
- byType:根据属性类型注入,如果容器内有多个这个类型的bean,那么容器如果不知道注入哪一个,就会报错.
(1) staticproxy: 通过代理类的对象,为原始类的对象(目标类的对象)添加辅助功能,更容易更换代理实现类,利于维护.
public class StaticProxyManager { public StaticProxyManager() { } }
代理类=实现原始类相同接口+添加辅助功能+调用原始类的业务方法.
静态代理的问题:
代理类数量过多,不利于项目的管理.
多个代理类的辅助功能代码冗余,修改时维护性差.
房子,房主,中介,租客
(2) jdkproxy: 代理对象和真实对象的关系,像是兄弟.代理对象对真实对象进行增强
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable { }
封装一个工具类,实现 InvocationHandler 接口,进行重写 getProxy 和 invoke 方法.
(3) cglibproxy: 代理对象和真实对象的关系,就像是父子.是子类对象对父类对象的增强
class CglibAopProxy implements AopProxy, Serializable { }
(1) AOP的概念
即面向切面编程,利用AOP可以对业务逻辑的各个部分进行隔离,从而使业务逻辑的各部分之间耦合度降低,提高程序的可重用性,提好了开发效率,通俗的讲,可以实现不修改源代码的方式,在核心业务里面添加新的功能
(2) AOP的作用
Spring的AOP编程即是通过动态代理类为原始类的方法添加辅助功能
(3) AOP的底层实现
AOP底层的原理就是动态代理,真正干活bean使代理bean,代理bean对真实bean功能增强
1 切点(Pointcut):真正要被增强的方法
@Pointcut(value = "execution(* delete(..))") public void point2(){ System.out.println("切点2"); }
2 通知(Advice): 增强的业务代码.可以为切入点添加额外功能,分为:
(1) 前置通知:
前置通知继承org.springframework.aop.MethodBeforeAdvice;
@Before("point1()") public void before(){ System.out.println("基于aspectj注解形式的前置通知,要求大家掌握"); }
(2) 后置通知:
后置通知继承org.springframework.aop.AfterReturningAdvice;
@After("point2()") public void after(){ System.out.println("基于aspectj注解形式的后置通知,要求大家掌握"); }
(3) 环绕通知:
环绕通知继承org.aopalliance.intercept.Methodlnterceptor;
@Around("point2()") public Object around(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("环绕前置"); Object result = joinPoint.proceed(); System.out.println("环绕后置"); System.out.println(result); return result; }
(4) 异常通知:
异常通知继承org.springframework.aop.ThrowsAdvice;
@AfterThrowing(value = "point2()",throwing = "ex") public void afterthrowing(Exception ex){ System.out.println("异常通知"); System.out.println("异常信息:"+ ex.getMessage()); }
(5) 最终通知.
@AfterReturning("point2()") public void afterreturning(){ //切点正常执行 没有异常 才会执行 最终通知 System.out.println("最终通知"); }
3 切面(Aspect): 切点 + 通知
结果先执行前置通知.但随着spring版本的不同,下面各个通知类的执行结果顺序并不相同 . 但是异常通知只有在出现异常是才会执行.
1 Schema-based(了解)
定义通知类(添加额外通知) , 定义bean标签 , 定义切入点(PointCut)形成切面(Aspect)
2 AspectJ
(1) xml配置形式
创建通知类 , xml配置 , 测试
(2) 注解形式
配置文件
<context:component-scan base-package="com.qf">context:component-scan> <aop:aspectj-autoproxy>aop:aspectj-autoproxy>
通知类
@Aspect // 当前类 是一个 切面类 @Component // 这个注解 表明 当前类的对象 是spring 管理的bean public class AspectJAnnoAdvice { // @Before 表示前置通知 //@Before("execution(* save(..))") //public void before(){ // System.out.println("基于aspectj注解形式的前置通知,要求大家掌握"); //} @Pointcut(value = "execution(* save(..))") public void point1(){ System.out.println("切点1"); } @Pointcut(value = "execution(* delete(..))") public void point2(){ System.out.println("切点2"); } @Before("point1()") public void before(){ System.out.println("基于aspectj注解形式的前置通知,要求大家掌握"); } @After("point2()") public void after(){ System.out.println("基于aspectj注解形式的后置通知,要求大家掌握"); } @Around("point2()") public Object around(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("环绕前置"); Object result = joinPoint.proceed(); System.out.println("环绕后置"); System.out.println(result); return result; } @AfterReturning("point2()") public void afterreturning(){ //切点正常执行 没有异常 才会执行 最终通知 System.out.println("最终通知"); } @AfterThrowing(value = "point2()",throwing = "ex") public void afterthrowing(Exception ex){ System.out.println("异常通知"); System.out.println("异常信息:"+ ex.getMessage()); } }
(1) @Component : 通用
@Component public class App { }
(2) @Service : 业务层专用
@Service(value = "userService") public class UserServiceImpl implements UserService { }
(3) @Controller : web层(Controller层)专用
@Controller @RequestMapping("/hello") // 访问路径,等价于url-pattern public class HelloController { }
(4) @Repository : dao层专用
@Repository public class UserJdbcDaoImpl implements UserDao { }
这四个注解功能是一样的,都可以用来创建bean实例
(1) @Autowired: 现根据类型注入,再根据名字注入
@Qualifier: 根据名称进行注入
@Autowired @Qualifier(value = "userDaoImpl1") private UserDao userDao;
(2) @Resource: 先根据名字注入,再根据类型注入
@Resource(name = "userDaoImpl1") //根据名称进行注入 private UserDao userDao;
@Value: 注入普通属性的注解
@Value(value = "abc") private String name;
@configuration: 替代xml配置文件
@Configuration //作为配置类,替代 xml 配置文件 @ComponentScan(basePackages = {"com.glls"}) public class SpringConfig { }
@ComponentScan(basePackages = {“com.hui”})
@Primary
@PostConstruct
@PreDestory
@Scope : 用户控制bean的创建模式
(1) @Aspect : 声明此类是一个切面类,会包含切入点(pointcut)和通知(advice)
@Aspect // 声明此类是一个切面类:会包含切入点(pointcut)和通知(advice) @Component //声明组件,进入工厂 public class MyAspect { }
(2) @Pointcut : 定义切入点
@Pointcut(value = "execution(* delete(..))") public void point2(){ System.out.println("切点2"); }
添加依赖 如附代码1
(1) 准备数据原配置文件 db.properties
jdbc.driver=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/ssm?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true jdbc.username=root jdbc.password=123456
(2) applicationContext.xml
附代码2
(1) 添加依赖
(2) logback.xml
附代码3
事务是数据库操作的基本单元,逻辑上的一组操作,要么都成功,要么都失败.也就是说只要一组操作中有一个失败了,那么这组操作都失败
ACID
(1) A:atomicity,原子性.一组操作整体不可拆分,要么都成功,要么都失败.
(2) C:consistency,一致性.数据在十五的前后哦,业务整体一致
(3) I:isolation,隔离性.事务之间,互相隔离
(4) D:durability,持久性.一旦事务执行成功,数据一定会落盘在数据库
(1) isolation:隔离级别
名称 描述 default (默认值)(采用数据库的默认的设置) (建议) read-uncommited 读未提交 read-commited 读已提交 (Oracle数据库默认的隔离级别) repeatable-read 可重复读 (MySQL数据库默认的隔离级别) serialized-read 序列化读 隔离级别由低到高为:read-uncommited < read-commited < repeatable-read < serialized-read
(2) 事务并发时的安全问题
问题 描述 脏读 一个事务读取到另一个事务还未提交的数据。大于等于 read-commited 可防止 不可重复读 一个事务内多次读取一行数据的相同内容,其结果不一致。大于等于 repeatable-read 可防止 幻影读 幻读,并不是说两次读取获取的结果集不同,幻读侧重的方面是某一次的 select 操作得到的结果所表征的数据状态无法支撑后续的业务操作。更为具体一些:select 某记录是否存在,不存在,准备插入此记录,但执行 insert 时发现此记录已存在,无法插入,此时就发生了幻读。mysql 幻读的详解、实例及解决办法 - SegmentFault 思否 (3) 数据库事务的操作.
附代码4
(1) 配置事务管理器.在applicationContext2.xml 中配置基于注解的事务DataSourceTransactionManager
事务管理器,其中持有DataSource,可以控制事务功能(commit,rollback等).
注意:DataSourceTransactionManager 和 SqlSessionFactoryBean 要注入同一个DataSource的Bean,否则事务控制失败!!!
<bean id="tx" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource">property> bean>
(2) 开启事务的注解
<tx:annotation-driven transaction-manager="tx"/>
(3) 在需要事务的方法上使用注解
@Transactional public void transferMoney(int from, int to, double money) { ...... }
(4) 注解
//@Transactional(isolation = Isolation.SERIALIZABLE) // 序列化读的隔离级别 可以避免脏读 不可重复读 幻读 @Transactional(isolation = Isolation.REPEATABLE_READ) // 可重复读的隔离级别 可以避免脏读 不可重复读 但是会出现 幻读 //@Transactional(isolation = Isolation.READ_COMMITTED) // 读已提交的隔离级别 可以避免脏读 但是会出现 不可重复读 幻读 //@Transactional(isolation = Isolation.READ_UNCOMMITTED) // 读未提交的隔离级别 会出现脏读 不可重复读 幻读 public List<Order> findOrderById(Integer id) { List<Order> list1 = orderMapper.findOrderByUserId(id); System.out.println(list1); System.out.println("----------------------"); List<Order> list2 = orderMapper.findOrderByUserId(id); return list1; }
面试题:
单例bean和多例bean的区别(默认是单例bean)
BeanFactory:是一个容器接口,是一个容器
FactoryBean:是一个bean,即工厂bean,产生bean的bean
spring中 当有 切面时 使用的bean 是动态代理对象,是在BeanPostProcessor bean的处理器方法的后置增强方法 替换的
3.spring 在生成动态代理对象时优先选择哪种方式–>jdk的方式
<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.0modelVersion>
<groupId>com.glls.java2301groupId>
<artifactId>smartifactId>
<version>1.0-SNAPSHOTversion>
<packaging>warpackaging>
<name>sm Maven Webappname>
<url>http://www.example.comurl>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<maven.compiler.source>1.8maven.compiler.source>
<maven.compiler.target>1.8maven.compiler.target>
properties>
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.2.9.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aspectsartifactId>
<version>5.2.9.RELEASEversion>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.12version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.18version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.4.6version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>5.2.9.RELEASEversion>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatis-springartifactId>
<version>1.3.2version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.1.16version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webartifactId>
<version>5.2.9.RELEASEversion>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>3.1.0version>
<scope>providedscope>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>jsp-apiartifactId>
<version>2.0version>
<scope>providedscope>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>jstlartifactId>
<version>1.2version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
<version>1.7.25version>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-coreartifactId>
<version>1.2.3version>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-classicartifactId>
<version>1.2.3version>
dependency>
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.17version>
dependency>
<dependency>
<groupId>org.logback-extensionsgroupId>
<artifactId>logback-ext-springartifactId>
<version>0.1.4version>
dependency>
dependencies>
<build>
<finalName>smfinalName>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-clean-pluginartifactId>
<version>3.1.0version>
plugin>
<plugin>
<artifactId>maven-resources-pluginartifactId>
<version>3.0.2version>
plugin>
<plugin>
<artifactId>maven-compiler-pluginartifactId>
<version>3.8.0version>
plugin>
<plugin>
<artifactId>maven-surefire-pluginartifactId>
<version>2.22.1version>
plugin>
<plugin>
<artifactId>maven-war-pluginartifactId>
<version>3.2.2version>
plugin>
<plugin>
<artifactId>maven-install-pluginartifactId>
<version>2.5.2version>
plugin>
<plugin>
<artifactId>maven-deploy-pluginartifactId>
<version>2.8.2version>
plugin>
plugins>
pluginManagement>
<resources>
<resource>
<directory>src/main/javadirectory>
<includes>
<include>**/*.xmlinclude>
includes>
resource>
<resource>
<directory>src/main/resourcesdirectory>
<includes>
<include>**/*.xmlinclude>
<include>**/*.propertiesinclude>
<include>**/*.iniinclude>
includes>
resource>
resources>
build>
project>
<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
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.glls.java2301">context:component-scan>
<aop:aspectj-autoproxy>aop:aspectj-autoproxy>
<context:property-placeholder location="classpath:db.properties" />
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="maxWait" value="60000"/>
<property name="timeBetweenEvictionRunsMillis" value="60000"/>
<property name="minEvictableIdleTimeMillis" value="300000"/>
bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource">property>
<property name="configLocation" value="classpath:mybatis-config.xml">property>
bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.glls.java2301.mapper">property>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory">property>
bean>
beans>
<configuration>
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<Target>System.outTarget>
<Encoding>UTF-8Encoding>
<encoder>
<pattern>%d{yyyy-MM-dd_HH:mm:ss.SSS} %5p [%t] [%c{1}]:%L - %m%n
pattern>
encoder>
appender>
<appender name="logfile"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<Encoding>UTF-8Encoding>
<encoder>
<pattern>%d %p [%t] [%c]:%L - %m%npattern>
encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>DEBUGlevel>
filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>log/%d{yyyy-MM-dd-HH'.log'}fileNamePattern>
rollingPolicy>
appender>
<logger name="org.springframework" level="WARN" />
<logger name="org.springframework.remoting" level="WARN" />
<logger name="org.springframework.scheduling.quartz" level="WARN" />
<logger name="org.springframework.data.jpa" level="DEBUG" />
<logger name="org.cometd" level="WARN" />
<logger name="ch.qos.logback" level="WARN" />
<logger name="com.springapp.mvc" level="DEBUG" />
<logger name="com.glls.java2301.mapper" level="DEBUG">logger>
<root level="ERROR">
<appender-ref ref="stdout" />
<appender-ref ref="logfile" />
root>
configuration>
SELECT @@tx_isolation; -- 查看 当前 隔离级别
SHOW VARIABLES LIKE 'autocommit' -- 查看自动提交 是否开启
SET autocommit=0; -- 关闭自动提交
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; -- 设置 读未提交 隔离级别 会出现脏读 不可重复度 幻读
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; -- 设置 读已提交 隔离级别 可出现 不可重复度 幻读
SET SESSION TRANSACTION ISOLATION LEVEL READ REPEATABLE READ; -- 设置 可重复度 隔离级别 可出现幻读
#步骤1
START TRANSACTION; -- 开启事务
UPDATE t_order SET productNum = 3 WHERE userId = 10;
#步骤3
-- 提交 或者 回滚
COMMIT; -- 提交事务
ROLLBACK; -- 回滚事务
vel=“DEBUG” />
```
SELECT @@tx_isolation; -- 查看 当前 隔离级别
SHOW VARIABLES LIKE 'autocommit' -- 查看自动提交 是否开启
SET autocommit=0; -- 关闭自动提交
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; -- 设置 读未提交 隔离级别 会出现脏读 不可重复度 幻读
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; -- 设置 读已提交 隔离级别 可出现 不可重复度 幻读
SET SESSION TRANSACTION ISOLATION LEVEL READ REPEATABLE READ; -- 设置 可重复度 隔离级别 可出现幻读
#步骤1
START TRANSACTION; -- 开启事务
UPDATE t_order SET productNum = 3 WHERE userId = 10;
#步骤3
-- 提交 或者 回滚
COMMIT; -- 提交事务
ROLLBACK; -- 回滚事务