https://www.bilibili.com/video/BV185411477k?p=142&spm_id_from=pageDriver
源自这个视频,讲的想到好,受益匪浅
什么是Spring
1.spring是一个轻量级的javaEE的解决方案 整合众多的- 优秀的设计模式
- 轻量级
- 1.面对运行环境没有额外的要求
- 2.开源 tomcat resion jetty
- 3.收费 webloginc websphere
- 4.2.代码移植性高
- 5.不需要实现额外的接口
javaEE解决方案
整合了设计模式
- 1.工厂
- 2.代理
- 3.模板
- 4.c策略
3.设计模式
- 广义的概念
- 面向对象设计中,解决特定问题的经典代码
- 2.侠义概念
- GOF4人帮的23种设计模式 工厂,适配器,装饰器,门面,代理,模板…
4.工厂设计模式
4.1. 什么是工厂设计模式
- 概念:通过工厂类 创建对象
-
User user= new User();
-
UserDAo userDao=new UserDaoImpl();
- 好处:解耦合
- 耦合:指定是代码间的强关联关系,一方的改变会影响到另一方
- 问题:不利于代码的维护
- 简单:把接口的实现类,硬编译在程序中
-
UserService userService=new UserServiceImple();
4.2. 简单工厂的设计
package com.baizhiedu.basic;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class BeanFactory {
private static Properties env = new Properties();
static {
try {
//第一步 获取io的输入流
InputStream inputStream = BeanFactory.class.getResourceAsStream("/applicationContext.properties");
//第二部文件内容 封装到Properties集合中 key= userService value=com.baizhiedu.basic.UserServiceImpl
env.load(inputStream);
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static UserService getUserService() {
/**
* 对象的创建方式
*
* 1.直接调用构造方法 创建对像 UserService userService=new UserServiceImpl();
* 2.通过反射的形式 创建对象 创建对象 解耦合
* Class clszz= Class.forName("com.baizhiedu.basic.UserServiceImpl");
* UserService userService= clazz.newInstance;
* */
UserService userService = null;
try {
Class clazz = Class.forName(env.getProperty("userService"));
userService = (UserService) clazz.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return userService;
//return new UserServiceImpl();
}
public static UserDao getUserDao() {
UserDao userDao1 = null;
try {
Class clazz = Class.forName(env.getProperty("userDao"));
userDao1 = (UserDao) clazz.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return userDao1;
}
}
4.3. 通用工厂的设计
问题:简单工厂会存在大量的臃余
通用工厂的代码
//创建一切想要的对象
public static Object getBean( String key){
Object ret=null;
try{
Class<?> clazz = Class.forName(env.getProperty(key));
ret=clazz.newInstance();
}catch (Exception e){
e.printStackTrace();
}
return ret;
}
4.4通用工厂的使用方式
- 1.定义类型
- 2.通过配置文件的配置告知工厂(applicationContext.properties)
- key=value
- 3.通过工厂获得类的对象
-
Object ret= BeanFactory.getBean("key");
5.总结
-
Spring本质 :工厂 ApplicationContext (applicationContext.xml)
第二章.第一个Spring程序
1.软件版本
- jdk 1.8+
- maven3.5+
- idea2018+
- springFramwork 5.1.4
- 官方网站www.spring.io
2.环境搭建
- spring的jar包
- 1.设置pom 依赖
-
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.10.RELEASE</version> </dependency>
-
. spring配置文件
-
配置文件的放置位置:任意位置,没有硬性的要求
-
配置文件的命名 :没有硬性的要求 建议:applicationContext.xml
-
思考:日后使用spring框架时 ,需要进行配置文件的设置
3.Spring的核心的APi
- applicationContext
- 作用:spring提供的ApplicationContext这个工厂,用于对象的创建
- 好处用于解耦合
- ApplicationContext接口类型
- 接口:屏蔽实现的差异
- 非web环境:classPathXmlApplicationContext(main junit)
- web环境下:xmlWebApplicationContext
- 重量级资源
- ApplicationContext工厂的对象占用大量的内存
- 不会频繁的创建对象:一个应用只会创建一个工厂对象
- ApplicationContext工厂:一定是线程安全的(多线程并发访问)
4.程序开发
1.1. 创建类型
2. 2.配置文件的配置 applicationContext.xml
3. <bean id="person" class="com.baizhiedu.basic.Person"/>
4.3. 通过工厂类获得对象
4. ApplicationContext
5. ClassPathXmlApplicationContext
6.
//获取Spring的工厂
ClassPathXmlApplicationContext xpx = new ClassPathXmlApplicationContext("/applicationContext.xml");
//2.通过工厂类来 获得对象
Person person =(Person) xpx.getBean("person");
System.out.println(person);
5.细节分析
- 名词解释
- spring工厂创建的对象,叫做bean或者组件(commponet)
- spring工厂的相关的方法
//获取Spring的工厂
ClassPathXmlApplicationContext xpx = new ClassPathXmlApplicationContext("/applicationContext.xml");
//2.通过工厂类来 获得对象 不需要强制类型的转换
Person person = xpx.getBean("person", Person.class);
System.out.println(person);
//当前spring配置文件中只能有一个(bean Class 是person类型)
Person person = xpx.getBean( Person.class);
System.out.println(person);
// 获取的是spring工厂配置文件的所有的bean标签的id值 person person1
String[] beanDefinitionNames = xpx.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
//根据类型获取Spring配置文件中对应的id值
String[] beanNamesForType = xpx.getBeanNamesForType(Person.class);
for (String s : beanNamesForType) {
System.out.println(s);
}
//用于判断是否存在指定的id值的bean
if (xpx.containsBeanDefinition("person")){
System.out.println("true"+true);
}else{
System.out.println("false"+false);
}
//用于判断是否存在id值bean
if(xpx.containsBean("persion")){
System.out.println(true);
}else{
System.out.println(false);
}
-
设置配置文件要注意的细节
- 只配置class属性
-
<bean class="com.baizhiedu.basic.Persion"/>
- a)上述这种配置 有没有id值 com.baizhiedu.basic.Persion#0
- b)应用场景:如果这个bean只需要使用一次,那么就可以省略id值
-
如果bean会使用多次,或者被其他bean应用则需要设置id值
-
2.name属性
-
作用:用于在spring的配置文件中为bean对象定义别名(小名)
- 相同:
-
1.ctx.getBean("id|name")--->object
-
2.<bean id=" " class=" "
- 等效
-
<bean name="" class="'
- 区别:
- 1.别名可以定义多个,但是id属性只能有一个值
-
2. xml的id属性 命名要求:必须以字母开头,字母 数字 下划线 连字符 不能以特殊字符开头 /person
- name 属性的值,没有要求 /person
- name 属性会应用在特殊的场景下:/person(Spring+struts1)
- xml 发展到今天:id属性的限制,不存在 /Person
- 3.代码
//用于判断是否存在指定的id值的bean 只能判断id 不能判断name
/** if (xpx.containsBeanDefinition("person")){
System.out.println("true"+true);
}else{
System.out.println("false"+false);
}
//用于判断是否存在id值bean 既可以判断id 也可以判断name
/** if(xpx.containsBean("persion")){
System.out.println(true);
}else{
System.out.println(false);
}
*/
6.Spring 工厂的底层实现原理(简约版)
-
spring 工厂是可以调用对象私有的构造方法创建对象
-
思考
-
问题:是不是在开发过程中,所有的对象,都会交给spring 工厂的来创建
-
回答:理论上是的,但是有特例:实体对象(entity) 是不会交给spring 创建 它是由持久层框架进行创建的.
第三章 spring5.x与日志框架的整合
1.spring与日志的框架进行整合,日志框架就可以在控制台中,输出spring框架运行过程中的一些重要的信息
2.好处:便于了解spring框架的运行过程,利于程序的调试 -
spring如何整合日志框架
-
spring 1.2.3早期是用 commons-loggng.jar
-
spring5.x 默认整合的日志框架 logback log4j2
- . Spring 5.x整合log4j
- 1.引入log4j jar包
-
2.引入log4.properties配置文件
-
-
pom
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
- log4j.properties
# resources 文件夹根目录下
### 配置根
log4j.rootLogger = debug,console
###日志输出到控制台显示
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Target=System.out
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
第四章 注入(injection)
1.什么是注入
1.通过Spring工厂以及配置文件,为所创建对象的成员变量赋值
-
1.1为什么需要注入
“通过编码的方式,为成员变量进行赋值,存在耦合”
1.2 如何进行注入(开发步奏)
- 配置spring的配置文件
<bean id="person1" name="p,p1" class="com.baizhiedu.basic.Person">
<property name="id">
<value>10</value>
</property>
<property name="name">
<value>小贱人</value>
</property>
</bean>
1.3注入的好处
-
解耦合
2.spring注入原理分析(简易版)
Set注入的详解
- 针对 于不同类型的成员变量,在标签,需要嵌套其他类型的标签
<property>
xxxx
</property>
1.jdk内置类型
1.1 String+8种基本数据类型
-
<value>suns</value>
1.2数组
<list>
<value>
suan@qq.com
</value>
<value>
ssdfsn@qq.com
</value>
<value>
ffffffsn@qq.com
</value>
</list>
1.3 Set集合
<set>
<value>18888</value>
<value>888888</value>
<value>999</value>
</set>
1.4 List集合
<list>
<value>上帝</value>
<value>仙女</value>
<value>仙女</value>
</list>
1.5 map集合
<map>
<entry>
<key><value>小件</value></key>
<value>很好</value>
</entry>
<entry>
<key><value>大件</value></key>
<value>很坏</value>
</entry>
</map>
1.6 Properties
<props>
<prop key="key1"> value1</prop>
<prop key="key2"> value2</prop>
<prop key="key3"> value3</prop>
</props>
1.7 复杂的jdk类型 Date
-
需要程序员自定义类型转换器,处理
2.用户自定义类型
- 为成员变量提供set get 方法
- 配置文件中进行注入(赋值)
<bean id="userService" class="XXXX.UserServiceImpl">
<property name="userDao">
<bean class="XXXXX.USerDaoImple"/>
</property>
</bean>
2.2第二种方式
- 第一种赋值方式存在问题
- 1.配置文件存在庸于
- 2.被注入的对象(UserDao),多次创建,浪费(jvm)内存资源
- 为成员变量提供set,get方法
- 配置文件中进行配置
<bean id="userDao" class="XXX.UserDaoImpl"/>
<bean id="userService" class="XXXX.UserServiceImpl">
<property name="userDao">
<ref bean="userDao"/>
</property>
</bean>
#Spring 4.x 废除了<ref local=""/>基本等效于<ref bean=" ">
- Set注入的简化的写法
3.1 基于属性简化
<property name="name">
<value>suns</value>
</property>
<property name="name" value="suns"/>
注意:通过 value属性 只能简化 8种基本数据类型+string 注入标签
//用户自定义类型
<property name="userDao">
<ref bean="userDao"/>
</property>
<property name="userDao" ref="userDao"/>
3.2 基于p命名
第六章 构造注入
- 注入:通过spring的配置文件,为成员变量赋值
- Set注入:Spring调用set方法,通过配置文件 为成员变量赋值
- 构造注入:Spring调用的构造方法 通过配置文件 为成员变量赋值
1.开发步奏
- 提供有构造方法
package com.baizhiedu.basic.construter;
import java.io.Serializable;
public class Customer implements Serializable {
private String name;
private int age;
public Customer(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Customer{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
- Spring 配置文件
<bean id="customer" class="com.baizhiedu.basic.construter.Customer">
<constructor-arg>
<value>suns</value>
</constructor-arg>
<constructor-arg>
<value>102</value>
</constructor-arg>
</bean>
- 方法的重载
2.1 当参数的构造个数不同时
1.通过控制<constructor-age>标签的数量进行区分
2.2 构造参数相同时
1通过在标签引入 type属性 进行类型的区分<constructor type=''>
3.注入的总结
- 未来的实战中,应用set注入还是构造注入?
答案:set注入更多
1.构造注入麻烦
2.Spring框架底层 大量应用了 set注入
第七章 反转控制 与依赖注入
- 反转控制( IOC Inverse of Control)
- 对成员变量的赋值
- 反转控制:把对于成员变量赋值的控制权,从代码中 反转(转移) 到Spring 工厂和配置文件中去完成.
3.好处:解耦合- 底层实现:工厂设计模式
- 依赖注入(Dependency Injecttion Di)
- 注入:通过spring工厂以及配置文件,为对象(bean 组件)的成员变量赋值
依赖注入:当一个类需要另一个类时,就意味着依赖,一旦出现依赖,就可以把另一个类作为本类的成员变量,最终通过Spring配置问价进行注入(赋值)
第八章.Spring 创建复杂对象
1.什么事复杂对象
复杂对象:指的就是不能直接通过new 构造方法创建的对象
Connection
SqlSessionFactory
2.Spring工厂创建复杂对象的的3种方式
- 开发步奏
-
实现factoryBean接口
-
Spring 配置文件的配置
-
#如果Class中指定的类型 是 FactoryBean接口剖的实现类,那么通过id值得的是这个类所创建的复杂对象 Connection
<bean id="conn" class="com.baizhiedu.factorybean.ConnectionFactoryBean"/>
- 细节
如果就想获得FactoryBean类型的对象,ctx.getBean("&conn")
获得是ConnectionFactoryBean对象
/**
* 测试FactoryBean工厂
*/
@Test
public void test13(){
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
ConnectionFactoryBean conn = (ConnectionFactoryBean) ctx.getBean("&conn");
System.out.println("conn="+conn);
}
- isStringleton方法
返回 true 只会创建一个复杂对象
返回false 每次会创建新的对象
问题:根据这个对象的特点,决定返回的是true(sqlSessionFactory)还是false(Connection) - mysql高版本的连接创建时,需要制定SSL证书,解决问题的方式
Connection conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/suns?useSSL=false","root","123456");
或者
url=“jdbc:mysql://localhost:3306/suns?useSSL=false”
- 依赖注入的体会(Di)
把ConnectionFactoryBean中依赖的四个字符串信息,进行配置文件的注入
好处:解耦合
在这里插入代码片
<bean id="conn" class="com.baizhiedu.factorybean.ConnectionFactoryBean">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/suns?useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
- FactoryBean的实现的原理
接口回调
1.为什么Spring规定FactoryBean接口实现 并且 getObject()?
2.ctx.getBean(“conn”)获得是复杂对象Connection 而没有获得ConnectionFactoryBean(&)
Spring内部运行流程
1.通过conn获得ConnectionFactory类的对象,进而通过instanceof 判断出是FactoryBean接口的实现类
2.Spring 按照规定调用 getObject()–>Connection
3.返回Connection
- FactoryBean总结
1.Spring 中用于创建复杂对象的一种方式,也是Spring原生提供的,后续讲解Spring整合其他框架时,大量使用FactoryBean
2.1 实例化工厂
- 避免spring框架的侵入
- 整合遗留系统
<bean id ="connFactory" class="com.baizhiedu.factorybean.ConnectionFactory"></bean>
<bean id="conn" factory-bean="connFactory" factory-method="getConnection"/>
2.3 静态工厂
- 开发步奏
<bean id="conn" class="com.baizhiedu.factorybean.StaticConnectionFactory" factory-method="getConnection"/>
第九章,控制Spring创建工厂对象的次数
- 如何控制简单对象的创建次数
<bean id="account" scope="singleton|prototype" class="xxxx.Account"/>
sigleton:只会创建一次简单对象的默认值
prototype:每一次都会创建新的对象
- 如何控制复杂对象的创建次数
FactoryBean(
isSingletion(){
return true 只会创建一次
return false ,每次都会创建新的
}
)
如果没有isSingleton方法 还是通过scope 属性来控制创建的次数
3. 为什么要控制创建的次数?
- 好处:节省不必要的内存的浪费
- 什么 样的对象只创建一次?
- sqlsessionFactory
- Dao
- Service
- 什么样的对象 每次都要创建新的?
- Connection
- Sqlsession |session
Struts2 Action
总结线程安全的只创建一次即可,线程不安全的 要 创建多次
第十章 对象的生命周期
- 什么是对象的生命周期
指的是一个对象创建,存活,消亡的一个完整的过程
- 为什么要学习对象的生命周期
由spring负责对象的创建,存活,销毁,了解生命周期,有利于我们使用Spring为我们创建的对象
- 生命周期的3个阶段
- 创建阶段
- Spring 工厂何时创建对象
- scope=“singleton”
- Spring 工厂创建的同时,对象的创建
注意:设置scope=singleton 这种情况下,也需要在获取对象的同时,创建对象
<bean lazy-init="true"/>
- scope =“prototype”
Spring 工厂会在获取对象的同时,创建对象
ctx.getBean(" ")
- 初始化阶段
Spring 在创建完对象后,调用对象的初始化方法,完成对应的初始化操作
- 初始化方法提供:程序员根据需求,提供初始化方法,最终完成初始化操作
2.初始化的方法调用:Spring工厂进行调用
- 实现initializingBean接口
//程序员根据需求 实现的方法,完成初始化
punlic void afterProperitesSet(){
}
- 对象提供一个普通的方法
public void myInit(){
}
<bean id="product" class="xxxx.Product" init-method="myInit">
- 细节
- 如果一个对象即实现InittializingBean同时又提供的 普通的初始化方法,顺序
1.1 InitializingBean
1.2 普通初始化方法
- 注入一定发生在初始化前面
- 什么叫初始化操作
- 资源的初始化“数据库 io 网络。。。
- 销毁阶段
Spring 销毁对象之前,会调用对象的销毁方法,完成销毁操作
- Spring 什么时候销毁所创建的对象?
ctx.close();
2.销毁方法:程序员根据自己的需求,定义销毁方法,完成销毁操作
调用:spring 工厂完成调用
- DisposableBean
pubilc void destroy() throws Exception{
}
- 定义一个普通的销毁方法
public void myDestroy() throws Exception{
}
< bean id="" class="" init-method="" destroy-method="myDestroy"/>
- 细节分析
- 销毁方法操作只适合于scope=“singleton”
- 什么叫销毁操作
- 主要指的就是 资源的释放操作 io.close() conection.close();
第十一章,配置文件参数化
1.把spring配置文件中需要修改的 字符串信息,转移到一个更小的额配置文件中
- Spring配置文件中存在需要经常修改的额字符串?
存在 以数据库连接相关的参数 代表
2.经常变化的字符串,在spring 的配置文件中,直接修改.
不利于维护(修改)
3.转移到一个小的配置文件(.properties)
利于维护(修改)配置文件参数化:有利于Spring配置文件的维护(修改)
1.配置文件参数的开发步奏
- 提供一个小的配置文件(.properties)
名字:随便
放置位置:随便
jdbc.driverClassName=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/suns?useSSL=false&allowPublicKeyRetrieval=true
jdbc.username=root
jdbc.password=123456
- Spring配置文件与小配置文件进行整合
<!--Spring配置文件与小配置文件的整合-->
<context:property-placeholder location = "classpath:/db.properties"/>
- 在Spring 配置文件中通过${key}获取小配置文件中对应的值
十二章 自定义类型转换器
- 类型转换器
作用:Spring通用类型转换器把配置文件中的字符串类型的数据,转换成了对象中的成员变量对应的类型的数据,进而完成了注入
- 自定义类型的转换器
- 原因:当spring内部都没有提供特定类型转换器时,而程序员在应用的过程中还需要使用,那么就需要程序员自己定义类型的转换器
- 类implements Converter 接口
public class MyDateConverter implements Converter<String,Date> {
/**
* convert方法作用:String----->Date
* SimpleDateFormat sdf=new SimpleDateFormat();
* sdf.parset(String)---->Date
* param:source 代表的是配置文件中 日期字符串<value>1999-08-18</value>
* return :当把转换好的Date作为convert方法的返回值后,Spring自动的为birthday属性进行注入赋值
* @param source
* @return
*/
@Override
public Date convert(String source) {
Date date=null;
try{
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
date = dateFormat.parse(source);
} catch (Exception e){
e.printStackTrace();
}
return date;
}
}
- 在spring 的配置文件中进行配置
- MyDateConverter对象创建出来
`<bean id="myDateConverter" class="xxx.myDateConverter"/>`
- 类的转换器的注册
目的:告知Spring框架,我们所创建的MyDateConverter是一个类型转换器
<!--Spring创建MyDateConverter类型转换器-->
<bean id="myDateConverter" class="com.baizhiedu.converter.MyDateConverter"/>
<!--用于注册类型转换器-->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<ref bean="myDateConverter"/>
</set>
</property>
</bean>
<bean id="person" class="com.baizhiedu.converter.Person">
<property name="name" value="涨三"/>
<property name="birthday" value="1999-08-18"/>
</bean>
- 细节
- MyDateConverter中的日期的格式,通过依赖注入的方式,由配置文件完成赋值
MyDateConverter.java
package com.baizhiedu.converter;
import org.springframework.core.convert.converter.Converter;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MyDateConverter implements Converter<String,Date> {
private String pattern;
public String getPattern() {
return pattern;
}
public void setPattern(String pattern) {
this.pattern = pattern;
}
/**
* convert方法作用:String----->Date
* SimpleDateFormat sdf=new SimpleDateFormat();
* sdf.parset(String)---->Date
* param:source 代表的是配置文件中 日期字符串<value>1999-08-18</value>
* return :当把转换好的Date作为convert方法的返回值后,Spring自动的为birthday属性进行注入赋值
* @param source
* @return
*/
@Override
public Date convert(String source) {
Date date=null;
try{
SimpleDateFormat dateFormat = new SimpleDateFormat(pattern);
date = dateFormat.parse(source);
} catch (Exception e){
e.printStackTrace();
}
return date;
}
}
applicationContext2.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-4.0.xsd
">
<!--Spring创建MyDateConverter类型转换器-->
<bean id="myDateConverter" class="com.baizhiedu.converter.MyDateConverter">
<property name="pattern" value="yyyy-MM-dd"/>
</bean>
<!--用于注册类型转换器-->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<ref bean="myDateConverter"/>
</set>
</property>
</bean>
<bean id="person" class="com.baizhiedu.converter.Person">
<property name="name" value="涨三"/>
<property name="birthday" value="1999-08-18"/>
</bean>
</beans >
- ConversionServiceFactoryBean定义 id属性值 必须 是 conversionService
- Spring 框架内置日期类型的转换器
日期格式:支持2020/05/03 不支持(2020-05-01)
<bean id="person" class="com.baizhiedu.converter.Person">
<property name="name" value="涨三"/>
<property name="birthday" value="1999/08/18"/>
</bean>
第十三章 后置处理Bean
BeanPostProcessor作用 :对Spring工厂所创建的对象,进行加工
AOP底层实现:
注意:BeanPostProcessor接口
xxx(){}
- 后置处理Bean的运行的原理分析
程序员实现BeanPostProcessor规定接口中的方法
Object postProcessBeforeInitiallization(Object bean String beanName)
作用:spring创建完对象,并进行注入后,可以运行Before方法进行加工
获得Spring创建好的对象:通过方法的参数
最终通过返回值交给Spring框架
Object postProcessAfterInitiallizetion(Object bean String beanName)
作用:Spring执行完对象的初始化操作后,可以运行after方法进行加工
获得Spring创建好的对象:通过方法的参数
最终通过返回值交给Spring框架
实现中:
很少处理Spring的初始化操作:没有必要区分Before After,只需要实现其中的一个方法即可
注意:
postProcessBeforeInitiallization
return bean对象
- BeanPostProcessor的开发步奏
- 类 实现 BeanPostProcessor 接口
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
Categroy categroy = (Categroy) bean;
categroy.setName("小可爱");
return categroy;
}
}
- Spring 的配置文件中进行配置
<bean id="myBeanPostProcessor" class="xxx.MybeanPostProcessor"/>
- BeanPostProcessor细节
BeanPostProcessor会对Spring工厂中所有的创建的对象进行加工。
所以做好加if(bean instanceof XXX)来判断
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if(bean instanceof Categroy){ Categroy categroy = (Categroy) bean;
categroy.setName("小可爱");}
return bean;
}
}
#AOP编程
第一章 静态代理模式
1.为什么需要代理设计模式
1.1问题
- 在javaEE分层开发中,哪个层次对于我们来讲最重要。
DAO---->Service—>Controller
javaEE分层开发中,最重要的是Service层
- Service层中包含了哪些代码?
Service层中=核心功能(几十行,上百行代码)+额外功能(附加功能)
- 核心功能
业务运算
DAO调用- 额外功能
2.1不属于业务
2.2可有可无
2.3代码量微小
2.4 列如 ,事务,日志,性能。。。。。
- 额外功能书写在Service层中好不好?
Service层的调用者的角度来讲(Controller):需要在Service层书写额外功能。 *软件设计者:Service层不需要额外的功能*
- 现实生活中的解决方案
-
代理设计模式
1.1概念通过代理类,为原始类(目标)增加额外功能
好处:有利于原始类的(目标)的维护1.2 名词解释
- 目标类 原始类
指的是 业务类(核心功能—>业务运算 DAO调用) - 目标方法,原始方法
目标类(原始类)中的方法 就是目标方法(原始方法)
3.额外功能(附加功能)
日志 事务 性能
1.3 代理开发的核心要素
代理类=目标类(原始类)+额外功能+原始类(目标类)实现相同的接口
房东---->public interface UserService{
m1
m2
}
UserServiceImpl implements UserService{
m1------>业务运算 DAO调用
m2
}UseServiceProxy implements UserService{
private UserServiceimpl UserService=new UserServiceimpl();
m1
m2}
- 目标类 原始类
1.4 编码
静态代理:为每一个原始类,手工编写一个代理类(.java .class)
1.5 静态代理存在的问题
- 静态类文件数量过多,不利于项目的管理
UserServiceImpl UserServiceProxy
OrderServiceImpl OrderServiceProxy- 额外功能维护性差(麻烦)
第二章,spring的动态代理开发
- Spring动态代理的概念
概念:通过代理类为原始类(目标类)增加额外的功能
好处:利于原始类(目标类)的维护
- 搭建开发环境
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.8</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.3</version>
</dependency>
- spring动态代理的开发
- 创建原始对象(目标对象)
public class UserServiceImpl implements UserService {
@Override
public void register(User user) { System.out.println("UserServiceImpl.register 业务运算+DAO");
}
@Override
public boolean login(String name, String password) { System.out.println("UserServiceImpl.login"); return true;
}
}
添加spring配置创建对象UserServiceImpl
<bean id="userService" class="com.baizhiedu.proxy.UserServiceImpl">
- 额外功能
MethodBeforeAdvice接口
额外功能书写在接口的实现中,运行在原始的方法执行之前运行额外功能。
public class Before implements MethodBeforeAdvice {
/**
* 作用:需要把运行在原始方法执行之前运行的额外功能,写在before方法中
*/
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("-----method before advice log-------");
}
}
配置文件
<bean id="before" class="com.baizhiedu.dymamic.Before"/>
- 定义切入点
切入点:额外功能加入位置
目的:由程序员根据自己的需要,决定额外功能加入给哪个原始方法
register
login
简单的测试:所有方法都做为切入点,都加入额外功能。
<aop:config>
<!-- 所有的方法 ,都作为切入点,加入额外的功能 Login register-->
<aop:pointcut id="pc" expression="execution(* *(..))"/>
</aop:config>
- 组装(2 3整合)
表达的含义:所有的方法 都加入 before的额外功能
<!-- 组装:目的把切入点 与 额外功能进行整合-->
<aop:advisor advice-ref="before" pointcut-ref="pc">
- 调用
目的:获的Spring工厂创建的动态代理对象,并且调用
ApplicationContext ctx=new ClassPathXmlApplicationContext("/applicationContext.xml");
注意:
- Spring的工厂通过原始对象的id值获得的是代理对象
- 获得代理对象后,可以通过生明接口类型,进行对象的存储
com.baizhiedu.proxy.UserService userService = (com.baizhiedu.proxy.UserService)ctx.getBean("userService");
userService.login("")
userService.register("")
4.动态代理细节分析
Spring 框架在运行时,通过D动态字节码技术,在jvm创建的,运行在jvm内部,等程序的结束后,会和jvm一起消失
什么叫动态字节码技术:通过第三个动态字节码框架,在jvm中创建对应的类的字节码,进而创建对象,当虚拟机结束,动态字节码消失
结论:动态代理不需要自定义类文件,都是在jvm虚拟机运行过程中动态创建的,所以不会造成静态代理,类文件数量过多,影响项目管理问题。
- 动态代理编程简化代理开发
- 在额外功能不改变的前提下,创建其他目标类(原始类)的代理对象时,只需要指定原始(目标)对象即可。
- 动态代理的额外功能的维护性大大增强
第三章动态代理的详解
- 额外功能的详解
- MethodBeforeAdvice分析(额外功能只能运行在原始方法之前)
public class Before1 implements MethodBeforeAdvice {
/**
*作用:需要把运行在原始方法执行之前运行的额外功能,书写在before方法中
* Method:额外功能所增加给的那个原始法方法
* login 方法
*
* register 方法
*
* showOrder方法
*
* Object[]:额外功能所增加给的那个原始方法的参数,String name,String password
* User
* Object:额外功能所增加的那个原始对象 UserServiceImpl
* OrderServiceImpl
*/
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("-----new method before advice log-------");
}
}
- before方法的3个参数在实战中,该如何使用
before 方法的参数,在实战中,会根据需要进行使用,不一定会用到,也有可能会用到
Servlet{ service(HttpRequest request,HttpResponse reponse){ request.getParameter("name")-----> response.getWriter()------->} }
- MethodIntercepor(方法拦截 器)
methodinterceptor接口:额外功能可以根据需要运行在原始方法之前 或者之后或者前后
public class Arround implements MethodInterceptor {
/**
*invoke 方法的作用:额外功能书写在invoke
* 额外功能 原始方法之前
* 原始方法 之后
* 原始方法执行之前 之后
* 确定:原始方法怎么运行
* 参数:MethodInvocation (Method):额外功能所增加给的那个原始的方法
* login
* register
* invocation.proceed()------>login运行
* register运行
* 返回值:Object:原始方法的返回值
* Date convert(String name)
*/
@Override
public Object invoke(MethodInvocation Invocation) throws Throwable {
System.out.println("----额外功能 log-----");
Object ret = Invocation.proceed();
return ret;
}
}
额外功能运行在原始方法执行之后
@Override
public Object invoke(MethodInvocation Invocation) throws Throwable {
Object ret = Invocation.proceed();
System.out.println("----额外功能 log-----");
return ret;
}
额外功能运行在原始功能之前之后
什么样的额外功能,运行在原始方法之前 之后都要添加?
事务
@Override
public Object invoke(MethodInvocation Invocation) throws Throwable {
System.out.println("----额外功能 前log-----");
Object ret = Invocation.proceed();
System.out.println("----额外功能 后log-----");
return ret;
}
额外功能运行在原始功能抛出异常的时候
- 原始功能:
package com.baizhiedu.proxy;
public class UserServiceImpl implements UserService {
@Override
public void register(User user) {
System.out.println("UserServiceImpl.register 业务运算+DAO");
throw new RuntimeException("测试异常");
}
@Override
public boolean login(String name, String password) {
System.out.println("UserServiceImpl.login");
return true;
}
}
额外功能:
@Override
public Object invoke(MethodInvocation Invocation) throws Throwable {
Object ret=null;
try {
ret = Invocation.proceed();
}catch (Exception e) {
System.out.println("----额外功能 后log-----");
e.printStackTrace();
}
return ret;
}
}
配置文件
<?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"
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-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
">
<bean id="userService" class="com.baizhiedu.proxy.UserServiceImpl"/>
<bean id="orderService" class="com.baizhiedu.proxy.OrderServiceImpl">
</bean>
<!--<bean id="before" class="com.baizhiedu.dymamic.Before"/>-->
<!-- <bean id="before" class="com.baizhiedu.dymamic.Before1"/>-->
<bean id="arround" class="com.baizhiedu.dymamic.Arround"/>
<aop:config>
<!-- 所有的方法 ,都作为切入点,加入额外的功能 Login register-->
<aop:pointcut id="pc" expression="execution(* *(..))"/>
<!-- 组装:目的把切入点 与 额外功能进行整合-->
<aop:advisor advice-ref="arround" pointcut-ref="pc"/>
</aop:config>
</beans >
MethodInterceptor影响原始方法的返回值
原始方法的返回值,直接作为invoke方法的返回值返回,MethodInterceptor不会影响原始方法的返回值
@Override
public Object invoke(MethodInvocation Invocation) throws Throwable {
Object ret = Invocation.proceed();
System.out.println("----额外功能 后log-----");
return ret;
}
MethodInterceptor影响原始方法的返回值
Invoke方法的返回值,不要直接返回原始方法的运行结果即可。
@Override
public Object invoke(MethodInvocation Invocation) throws Throwable {
Object ret = Invocation.proceed();
System.out.println("----额外功能 后log-----");
return false;
}
2.切入点详解
切入点决定额外功能加入位置(方法)
<aop:pointcut id="pc" expression="execution(* *(..))"/>------>匹配了所有的方法 a b c
1.execution() 切入点函数
2.* *(..)切入点表达式
2.1 切入点表达式
1.方法切入表达式
* *(..)--->所有方法
* ----->修饰符 返回值
* ------>方法名
()----->参数表
.. --------->对于参数没有要求(参数有没有,参数有几个都行,参数是什么类型都行)
-
定义login方法作为切入点
* login(..) # 定义registter作为切入点 * register(..)
-
定义login方法且login方法有两恶搞字符串类型的参数,作为切入点
* login(String ,String) #注意:非java.lang包中的类型,必须写全限定名 * register(com.baizhiedu.proxy.User) # ..可以和具体的参数类型连用 * login(String ,..)-----login(String),login(String,String),login(String,com.baizhiedu.proxy.User)
-
精准方法的切入点限定
修饰符 返回值 包. 类. 方法(参数)
* com.baizhiedu.proxy.UserServiceImple.login(..)
* com.baizhiedu.proxy.UserServiceImpl.login(String,String)
-
类切入点
指定特定的类作为切入点(额外功能加入的位置),自然这个类中的所有的方法,都会加上对应的额外功能
-
语法1
#类中的所有的方法加入了额外功能 * com.baizhiedu.proxy.UserServiceImpl.*(..)
-
语法2
# 忽略包 1.类只有一级包 com。UserServiceImpl * *.UserServiceImpl.*(..) 2. 类存在多级包 com.baizhiedu.proxy.USerServiceImpl 3. * *..UserServiceImpl.*(..)
-
包切入点表达式 实战
指定包作为额外功能加入的位置,自然包中的所有类以及其方法都会加入额外的功能
-
语法1
#切入点包中的所有类,必须在proxy中,不能再proxy包的子包中 * com.baizhiedu.proxy.*.*(..)
-
语法2
#切入点当前包,以及其子包都生效 * com.baizhiedu.proxy..*.*(..)
2.2切入函数
切入点函数:用于执行切入点表达式
-
execution
最为重要的切入点函数,功能最全 执行 方法切入点表达式 类切入点表达式,包切入点表达式 弊端:execution执行切入点的表达式,书写麻烦 execution(* com.baizhiedu.proxy..*.*(..)) 注意:其他的切入点函数 简化是execution书写复杂度,功能上完全一至
-
args
作用:主要用于函数(方法)参数匹配 切入点:方法参数必须得是两个字符串类型得参数 exectution(* *.(String,String)) args(String,String);
3.within
作用:主要用于进行类,包切入点表达式得匹配
切入点:UserServiceImpl这个类
exection(* *..UserServiceImpl.*(..))
within(*..UserServiceImpl)
execution(* com.baizhiedu.proxy..*.*(..))
within(com.baizhiedu.proxy..*)
-
@annotation
作用:为具有特殊注解的方法加入额外功能 <aop:pointcut id="pc" expression="@annotation(com.baizhiedu.Log)"/>
自定义注解
package com.baizhiedu;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
}
-
切入点函数的逻辑运算
指的是 整合多个切入点函数一起配合工作,进而完成复杂的需求
-
and与操作
案例:login 同时 参数 2个字符串 1. excution(* login(String,String)) 2. excution(* login(..)and args(String,String)) 注意:与操作不同用于用于同种类型的切入点函数 #案例:register 方法 和login方法作为切入点 execution(* login(..))and execution(* register(. .))//错误 execution(* login(..))or execution(* register(. .))
-
or 或操作
#案例:register 方法 和login方法作为切入点 execution(* login(..))or execution(* register(. .))
-
第四章AOP编程
1.AOP概念
AOP(Aspect Oriented Programing) 面向切面编程=Spring 动态代理开发
以切面为基本单位的程序开发,通过切面编间的彼此协同,相互第哦啊用,完成程序的构造
切面=切入点+额外功能
OOP(Object Oritened Programing) 面向对象的编程 java
以对象为基本单位程序开发,通过对象间的彼此协同,相互调用,完成程序的构建
Pop(Producer Oriented Programing) 面向过程的(方法 函数) c语言
以过程为基本单位的程序开发,通过过程的间的彼此协同,相互调用,完成程序的构建。
Aop的概念:
本质就是Spring得动态代理开发,通过代理类为原始类增加额外得功能
好处:利于原始类得维护
注意:Aop编程不可代替oop,oop编程有意补充
2.Aop编程得开发步奏
原始对象
额外功能(MethodInterCeptor)
切入点
组装切面(额外功能+切入点)
3.切面得名词解释
切面=切入点+额外功能
几何学
面=点+相同的性质
第五章 Aop得底层实现得原理
-
核心问题
1.Aop如何创建动态代理类(动态字节码技术) 2.Spring工厂如何加工创建代理对象 通过原始对象得id值,获得的是代理对象。
2. 动态代理的创建
2.1 JDk的动态代理
- Proxy.newProxyInstance 方法参数的详解
- 编码
import com.baizhiedu.proxy.User;
import com.baizhiedu.proxy.a.UserService;
import com.baizhiedu.proxy.a.UserServiceImpl;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class TestJDKProxy {
/**
* 1.借用类加载器 TestJDKProxy
* UserServiceImpl
* 2.Jdk8.x以前
* final UserServiceImpl userService = new UserServiceImpl();
*/
public static void main(String[] args) {
//1.创建原始对象
UserServiceImpl userService = new UserServiceImpl();
//2.JDK创建动态代理
/**
*
*/
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("------proxy log------");
//原始方法运行
Object ret = method.invoke(userService, args);
return ret;
}
};
UserService userServiceProxy = (UserService) Proxy.newProxyInstance(TestJDKProxy.class.getClassLoader(), userService.getClass().getInterfaces(), handler);
userServiceProxy.login("login", "123456");
userServiceProxy.register(new User());
}
}
2.2 CGlib的动态代理
1.CGlib创建动态代理的原理:父子继承创建代理对象,原始类作为父类,代理类作为子类,这样既可以保证2者方法一致,同时在代理类中提供新的实现(额外功能+原始方法)
-CGlib编码
package com.baizhiedu.cglib;
import com.baizhiedu.proxy.User;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class TestCglib {
public static void main(String[] args) {
//创建原创对象
UserService userService = new UserService();
/**
* 通用cglib方式创建动态代理对象
* proxy。newProxyInstance(classloader,interface,invocationhandler)
* Enhancer.setClassLoader();
* Enhancer.setSuperClass();
* Enhancer。setCallback();-----》MethodInterceptor(cglib)
* Enhancer.create()---->代理
*
*/
Enhancer enhancer = new Enhancer();
enhancer.setClassLoader(TestCglib.class.getClassLoader());
enhancer.setSuperclass(userService.getClass());
MethodInterceptor interceptor = new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("----cglib log----");
Object ret = method.invoke(userService, args);
return ret;
}
};
enhancer.setCallback(interceptor);
UserService userServiceProxy = (UserService) enhancer.create();
userServiceProxy.login("小可爱","123456");
userServiceProxy.register(new User());
}
}
-
总结
1.Jdk动态代理 Proxy.newProxyInstance() 通过接口创建的实现类 2.Cglib动态代理 Enahancer 通过继承父类创建的代理类
- Spring工厂如何加工原始对象
- (Spring工厂对于代理的加工)
-
思路分析
-
编码
ProxyBeanPostProcessor.java
package com.baizhiedu.factory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class PoxyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Override
/**
* Proxy.newProxyInstance()
*/
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("-----new Log------");
Object ret = method.invoke(bean, args);
return ret;
}
};
Object mm = Proxy.newProxyInstance(PoxyBeanPostProcessor.class.getClassLoader(), bean.getClass().getInterfaces(), handler);
return mm;
}
}
配置文件
<?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"
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-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
">
<bean id="userService" class="com.baizhiedu.factory.UserServiceImpl"/>
<!--1.实现beanPostProcessor 进行加工-->
<!--2.配置文件中对beanPostProcessor进行处理-->
<bean id="proxyBeanPostProcessor" class="com.baizhiedu.factory.PoxyBeanPostProcessor"/>
</beans >
第六章 基于注解的AOP编程
1.基于注解的开发步奏
1.原始对象
2.额外功能
3.切入点
4.组装切面
#t通过切面类 定义了 额外功能 @Arround
定义了 切入点 @arround("execution( * login(..))")
@Aspect 切面类
package com.baizhiedu.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
/**
* 1.额外功能
* public Class MyArround implements MethodInterceptor{
* public Object invoke(MethodInvocation invocation){
* Object ret= invocation.proceed();
* return ret;
* }
*
*
* }
* 2.切入点
* <aop:config
* <aop:pointcut id="" expression="execution(* login(..))"/>
* >
* 3.组装
*/
@Aspect
public class MyAspect {
@Around("execution(* login(..))")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("---log-----");
Object ret = joinPoint.proceed();
return ret;
}
}
注解
<?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"
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-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
">
<bean id="userService" class="com.baizhiedu.factory.UserServiceImpl"/>
<!--切面
实现了
1.额外功能
2.切入点
3.组装
-->
<bean id="around" class="com.baizhiedu.aspect.MyAspect"/>
<!--告知spring基于注解进行aop编程-->
<aop:aspectj-autoproxy/>
</beans >
加@Aspect注解的称为切面类
2.细节
- 切入点的复用
切入点服用:在切面定义一个函数,上面@pointcut注解, 通过这种方式,定义切入点的表达式,后续更有利于切入点的 复用.
package com.baizhiedu.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
/**
* 1.额外功能
* public Class MyArround implements MethodInterceptor{
* public Object invoke(MethodInvocation invocation){
* Object ret= invocation.proceed();
* return ret;
* }
*
*
* }
* 2.切入点
* <aop:config
* <aop:pointcut id="" expression="execution(* login(..))"/>
* >
* 3.组装
*/
@Aspect
public class MyAspect {
@Pointcut("execution(* login(..))")
public void myPointcut(){}
@Around(value = "myPointcut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("---log-----");
Object ret = joinPoint.proceed();
return ret;
}
@Around(value = "myPointcut()")
public Object around1(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("---log tx-----");
Object ret = joinPoint.proceed();
return ret;
}
}
-
动态代理的创建方式
Aop底层实现 2种代理的创建方式 1.jdk 通过 实现接口 做新的实现类方式 创建代理对象 2. Cglib通过继承父类 做新的子类 创建动态代理对象 # 默认情况下 Aop编程,低层应用的是JDK动态代理创建方式 如果切换Cglib怎么做? <!--告知spring基于注解进行aop编程--> proxy-target-class="true"
1.基于Aop注解
<!--告知spring基于注解进行aop编程-->
<aop:aspectj-autoproxy proxy-target-class="true"/>
2.传统的Aop开发
<aop:config proxy-target-class="true">
<!-- 所有的方法 ,都作为切入点,加入额外的功能 Login register-->
<aop:pointcut id="pc" expression="@annotation(com.baizhiedu.Log)"/>
<!-- 组装:目的把切入点 与 额外功能进行整合-->
<aop:advisor advice-ref="arround" pointcut-ref="pc"/>
</aop:config>
第七章 AOP开发的坑
坑:在同一个业务种,进行业务方法间的相互相互调用,只有最外层的方法,才是加入了 额外功能(内部的方法,通过普通方式的第哦啊用,都调用的是原始的方法),如果想让人曾的方法也调用代理对象的方法,就要ApplicationContextAwrra 获得工厂,进而会的代理对象
package com.baizhiedu.aspect;
import com.baizhiedu.Log;
import com.baizhiedu.aspect.UserService;
import com.baizhiedu.basic.User;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class UserServiceImpl implements UserService, ApplicationContextAware {
private ApplicationContext ctx;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.ctx=applicationContext;
}
@Log
@Override
public void register(User user) {
System.out.println("UserServiceImpl.register 业务运算+Dao");
//调用的是原始对象的Login方法--->核心功能
/**
* 设计目的:代理对象的login方法--->额外功能+核心功能
*ApplicationContext ctx= new ClassPathXmlApplicationContext("applicationContext4.xml");
* UserService userService= (UserService)ctx.getBean("userService");
* userService.login("sss","123");
*
*/
UserService userService =(UserService) ctx.getBean("userService");
userService.login("sss","123");
}
@Log
@Override
public boolean login(String name, String password) {
System.out.println("UserServiceImpl.login");
return true;
}
}
配置文件
<?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"
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-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
">
<!--<bean id="userService" class="com.baizhiedu.proxy.a.UserServiceImpl"/>-->
<!--<bean id="orderService" class="com.baizhiedu.proxy.OrderServiceImpl"/>-->
<bean id="userService" class="com.baizhiedu.aspect.UserServiceImpl">
</bean>
<!--<bean id="before" class="com.baizhiedu.dymamic.Before"/>-->
<!-- <bean id="before" class="com.baizhiedu.dymamic.Before1"/>-->
<bean id="arround" class="com.baizhiedu.dymamic.Arround"/>
<aop:config proxy-target-class="true">
<!-- 所有的方法 ,都作为切入点,加入额外的功能 Login register-->
<aop:pointcut id="pc" expression="@annotation(com.baizhiedu.Log)"/>
<!-- 组装:目的把切入点 与 额外功能进行整合-->
<aop:advisor advice-ref="arround" pointcut-ref="pc"/>
</aop:config>
</beans >
Aop第八章 总结
Spring与持久层整合
第一章 持久层整合
-
Spring为什么要与持久层整和?
1.javaEE 开发需要持久层进行数据库的操作 2.jdbc Hibernate Mybatis 惊醒持久开发的过程存在大量的代码庸于 3.spring基于模板设计模式 对于上述的持久层技术进行了封装
-
Spring可以与那些持久层技术进行整合
第二章
-
mybatis 开发步奏的回顾
-
mybatis 在开发过程中存在的问题
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210421203632532.png)
-
Spring整合思路
spring 与Mybatis整合的开发步骤
<!--只需要配置一次-->
<bean id="dataSource" class=""/>
<!-- 创建SqlSessionFactory-->
<bean id="ssfd" class="SqlSessionFactoryBean">
<property name="dataSource" ref=""/>
<property name="typeAliasesPackage">
<!-- 指定 实体类所在的包 com.baizhiedu.mybatis.User -->
</property>
<property name="mapperLocations">
<!-- 指定 配置文件(映射文件)的路径 还有通用配置-->
com.baizhiedu.mapper/*Mapper.xml
</property>
</bean>
<!--DAO接口的实现类
session========>session.getMapper()======>xXXXDAO实现类对象
XXXDAO====>xxxDAO
-->
<bean id="scanner" class="MapperScannerConfigure">
<property name="sqlSessionFactoryBeanName" value="ssfd"/>
<property name="basePacakge">
指定 DAo接口放置的包 com.baizhiedu.dao
</property>
</bean>
-
编码
1. 实体 2. 表 3. 3.创建DAO接口 4. 实现Mapper文件
-
pom.xml
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.23</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.3</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.9</version>
</dependency>
- Spring的配置文件
<?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="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/suns?characterEncoding=utf8&serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<!-- 创建SqlSessionFactory SqlsessionFactoryBean-->
<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="typeAliasesPackage" value="com.baizhiedu.entity">
<!-- 指定 实体类所在的包 com.baizhiedu.mybatis.User -->
</property>
<property name="mapperLocations">
<!-- 指定 配置文件(映射文件)的路径 还有通用配置-->
<!-- com.baizhiedu.mapper/*Mapper.xml-->
<list>
<value>classpath:com.baizhiedu.mapper/*Mapper.xml</value>
</list>
</property>
</bean>
<!--DAO接口的实现类
session========>session.getMapper()======>xXXXDAO实现类对象
XXXDAO====>xxxDAO
-->
<bean id="scanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryBean"/>
<property name="basePackage" value="com.baizhiedu.dao">
<!-- 指定 DAo接口放置的包 com.baizhiedu.dao-->
</property>
</bean>
<bean id="userService" class="com.baizhiedu.service.UserServiceImpl"/>
</beans>
- Spring与mybatis的整合细节
第三章Spring的事务处理
-
什么是事务?
-
如何控制事务?
-
Spring控制事务的开发
-
spring控制事务的编码
-
搭建开发环境
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.1.14.RELEASE</version> </dependency>
-
编码
<bean id="userService" class="com.baizhiedu.service.UserServiceImpl">
<property name="userDao" ref="userDao"/>
</bean>
<!--spring提供的 配置额外功能的方法 增加事务
DateSourceTransactionManage
-->
<bean id="dateSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--配置切入点 额外功能加入切入点-->
<tx:annotation-driven transaction-manager="dateSourceTransactionManager"></tx:annotation-driven>
service.java
package com.baizhiedu.service;
import com.baizhiedu.dao.UserDao;
import com.baizhiedu.entity.User;
import org.springframework.transaction.annotation.Transactional;
@Transactional
public class UserServiceImpl implements UserService {
private UserDao userDao;
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void register(User user) {
userDao.save(user);
}
}
- 细节
<!--配置切入点 额外功能加入切入点-->
<tx:annotation-driven transaction-manager="dateSourceTransactionManager" proxy-target-class="true"/>
//其中的true flase 控制着jdk 代理和cglib代理的切换
默认: false jdk
true Cglib
Spring 的事务属性(transaction Attribute)
1. 什么是事务属性
2. 如何添加事务属性
3.事务属性的详解
- 隔离属性的概念
-
事务并发产生的问题
-
脏读
一个四和五,读取了另一个事务中国没有提交的数据,会在本事务中产生数据不一致的问题 解决方案:@transactional(isolation = Isolation.READ_COMMITTED)
-
不可重复读
一个事务中,多次读取相同的数据,但是读取结果不一样,会在本事务中产生数据不一致的问题 注意:1.不是脏读2.一个事务中 解决方案:isolation = Isolation.REPEATABLE_READ 本质:一把行锁
-
-
幻读
一个事务中,多次对整表进行查询统计,但是结果不一样,会在本事务中产生数据不一致的问题. 解决方案:isolation = Isolation.SERIALIZABLE 本质:表锁.
- 总结
事务属性
- 数据库对隔离属性的 支持
-
默认的隔离属性
ISOLATION_DEFAULT 会调用不同数据库的默认隔离级别属性 Mysql:REPEATABLE_READ Oracle:READ_COMMETTED
-
查看数据库的默认隔离级别
- 隔离属性(建议使用默认值)
- 传播属性
2.1 事务嵌套视图:
- 传播属性的值 及其用法
-
Required
-
Supports
-
默认的传播属性
required是传播属性的默认值
-
推荐传播属性的使用方法
增 删改方法:直接使用默认值的required 查询 操作:显示指定传播属性的值为supports
-
requires_new
-
只读属性(readOnly)(用于快速查找增加速度)
针对只进行查询的操作的业务方法,可以加入只读属性,提高运行效率 默认值为false
@Transactional(isolation = Isolation.SERIALIZABLE)
public class UserServiceImpl implements UserService {
private UserDao userDao;
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void register(User user) {
userDao.save(user);
//throw new RuntimeException("测试");//这个如果抛出异常 那么save()失败,说明加事务成功,
}
/**
*查询时用事务中的这两个方法,会事半功倍
*
* @param name
* @param password
*/
@Override
@Transactional(propagation = Propagation.SUPPORTS,readOnly = true)
public void login(String name, String password) {
}
}
-
超时属性
指定了事务等待的最长时间 1. 为什么事务进行等待? 当前事务的访问数据时,有可能访问的数据被别的事务进行加锁的处理,那么此时的事务就必须进行等待. 2. 等待时间为秒数 3. 如何应用 @Transactional(timeout=2); 4. 超时属性的默认值 -1 最终由对应的数据库来指定
@Transactional(timeout = 2)
public class UserServiceImpl implements UserService {
private UserDao userDao;
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void register(User user) {
//定义超时属性
try{Thread.currentThread().sleep(Long.parseLong("3000"));
userDao.save(user);}catch (Exception e){
e.printStackTrace();
}
//throw new RuntimeException("测试");//这个如果抛出异常 那么save()失败,说明加事务成功,因为复合事务的一致性
}
/**
*查询时用事务中的这两个方法,会事半功倍
*
* @param name
* @param password
*/
@Override
public void login(String name, String password) {
}
}
-
事务的异常属性
Spring事务处理过程中
默认 对于RuntimeException 及其子类 采用的是回滚的策论
默认 对于Exception以其子类 采用的是提交的策略
rollbackFor=(java.lang.Exception.xxx.xxx)
noRollbackFor={java.lang.RuntimeException.xxx.xx}@Transactional(rollbackFor ={java.lang.Exception.class} ,noRollbackFor = {java.lang.RuntimeException.class}) 建议:实战中使用RuntimeException={及其子类,使用事务异常属性的默认值.}
4. 事务属性常见配置总结
5.基于标签的事务配置方式(事务开发的第二种方式)
基于注解@Transaction的事务配置回顾
第一原始对象
<bean id="userService" class="com.baizhiedu.service.UserServiceImpl">
<property name="userDao" ref="userDao"/>
</bean>
<!--spring提供的 配置额外功能的方法 增加事务
DateSourceTransactionManage
-->
第二额外功能
<bean id="dateSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
///切入点
<!--配置切入点 额外功能加入切入点-->
@Transactionnal(isolation=,propagation=....)
public class UserServiceImpl implements UserService{
private UserDao userDao
///切入点与 额外功能完美整合
<!--额外功能,与注解完美的整合-->
<tx:annotation-driven transaction-manager="dateSourceTransactionManager" proxy-target-class="true"/>
事务属性
<tx:advice id="txAdvice" transacation-manager="dataSourceTransactionManager">
<tx:method name="register" isoloation="",propagation=""> </tx:method>
<tx:method name="login" ......></tx:method>
等效于
@Transactional(isolation=,propsgation=)
public void register(){
}
</tx:advice>
<aop:config>
//切入点
<aop:pointcut id="pc" epression="execution(* com.baizhidu.service.USerServiceImpl.regist(..))">
</aop:pointcut>
//组装
<aop:advisor advice-ref="txtAdvice" pointcut-ref="pc">
</aop:advice>
</aop:config>
- 基于标签的事务配置在实战中的应用(service包哪个方法,或者类加@Transactional 就会在哪个类或者方法上加上事务,以及所配置 的属性)
<?xml version="1.0" encoding="utf-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
">
<bean id="dateSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--<tx:advice id="txAdvice" transaction-manager="dateSourceTransactionManager">-->
<!-- <tx:attributes>-->
<!-- <tx:method name="register" isolation="DEFAULT" propagation="REQUIRED"/>-->
<!-- </tx:attributes>-->
<!--</tx:advice>-->
<!--编程的时候 service包中负责进行增删改操作的方法,都以modify开头
查询操作,命名无所谓
-->
<tx:advice id="txAdvice" transaction-manager="dateSourceTransactionManager">
<tx:attributes>
<!--代表以modify开头的增删改的方法会添加事务的指定属性-->
<tx:method name="modify*" />
<!--除了除了增删改其他用modify开头,其他用什么命名无所谓-->
<tx:method name="*" isolation="DEFAULT" read-only="true" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!--<aop:config>-->
<!-- <aop:pointcut id="pc" expression="execution(* com.baizhiedu.service.UserServiceImpl.register(..))"/>-->
<!-- <aop:advisor advice-ref="txAdvice" pointcut-ref="pc"/>-->
<!--</aop:config>-->
<!-- 应用的过程中,service放置到service包中-->
<aop:config>
<aop:pointcut id="pc" expression="execution(* com.baizhiedu.service..*.*(..)"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pc"/>
</aop:config>
pom.xml文件配置
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.20</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.1.14.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.3</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.18</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.15</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>
spring 和mvc整合
第一章 mvc框架整合思想
1. 搭建web运行环境
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.20</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.1.14.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.3</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.18</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.15</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
2. 为什么要整合mvc框架
1.mvc框架提供了控制器(Controller)调用Service
dao----》service
2.请求响应的处理
3.接受请求的参数 request。getParameter(“”)
4.控制程序的运行流程
5.视图解析(jsp json freemarker Thyemeleaf)
3. spring可以整合哪些mvc框架?
1.struts1
2.webwork
3.jsf
4.struts2
5.springmvc
4. spring 整合mvc框架的核心思想
- 准备工厂
- 代码整理
3. Spring 开发过程中多配置文件的处理
-
通配符方式
-
<import标签
applicationContext.xml 目的 整合其他配置内容 <import resource="applicationContext-dao.xml"/> <import resource="applicationContext-service.xml"/> <import resource="applicationContext-action.xml"/> 1.非web环境 new ApplicationContext ctx= ClassPathXMLApplicationContext("/applicationContext.xml"); 2.web环境下 <context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:applicationContext.xml</param-value> </context-param>
-
Spring注解编程
第一章
1. 什么是注解编程
2.为什么要讲注解注解编程?
3. 注解的作用
-
替换xml这种配置形式,简化配置
-
替换接口,实现调用双方的契约性
通 过注解的方式,在功能调用者和功能的提供者之间达成的达成的约定,进而进行功能的调用,因为注解应用更为灵活,所以现在的开发中,更加推荐通过注解的形式,完成。
4.spring注解的发展历程
5.注解开发的问题
第二章,spring的基础注解(Spring2.x)
1.对象创建相关注解
- 搭配开发环境
applicationContext.xml
<context:component-scan base-package="com.baizhiedu"/>
作用:让spring框架在设置包以及子包中扫描对应的注解,使其生效。
-
对象相关的注解
-
@Component
作用:替换原有spring配置 配置的文件中的<bean标签 注意: id属性 component注解 提供了默认的设置方式,首单词字母单词小写,Class属性 通过反射获得class 内容
-
-
@Component 细节
-
如何显示指定工厂创建对象的id值
@Component("u")
-
Spring配置文件覆盖注解配置内容
applicationContext.xml <bean id="u" class="com.baizhiedu.bean.User"/> id值 class的值 要和 注解中的设置保持一致。否则就会创建一个新的值
-
@Component的衍生注解
-
@Scope注解
//@Scope("singleton") @Scope("prototype")
-
- @lazy
- 生命周期相关的注解
package com.baizhiedu.life;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@Component
public class Product {
@PostConstruct
// scope为默认值时工厂创建之后被调用
public void myInit(){
System.out.println("Product.myInit");
}
@PreDestroy
//工厂关闭之前被调用
public void myDestory(){
System.out.println("Product.myDestory");
}
}
2.注入相关注解
-
用户自定义注入类型@Autowired
加入注解前
加入注解后
@Autowired 细节【推荐】
1.Autowired 注解基于类型进行注入 基于类型的注入:注入对象的类型,必须与目标成员变量类型相同或者是其子类(实现类)
Autowired Qualifier 基于名字注入【了解】
基于名字的注入:注入对象的id值,必须与qualifier注解中设置的名字相同
3.autowired注解放置位置
a)放置在对应成员变量的set方法上
spring会通过set方法为成员变量赋值
b)直接放置在这个放在成员变量上,
Spring通过反射直接对成员变量进行注入(赋值)【推荐】
4.javaEE规范中类似功能的注解
JSR250 @Resouce(name="userDAoImpl") 基于名字进行注入
等同 = @Autowired()
@Qualifier("userDAoImpl")
注意:如果在应用Resource注解时,名字没有配对成功,那么他会继续按照类型进行注入
总结
-@ PropertySource
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210424231441669.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzUyOTQ2MTA0,size_16,color_FFFFFF,t_70)
-
@value注解使用细节
-
@value注解不能应用在静态成员变量上
如果应用,赋值(注入)失败
-
@value注解+Properties这种方式,不能注入集合类型
Spring提供新的配置形式 YAML YML(springBoot)
-
3.注解扫描详解
<context:component-scan base-package="com.baizhiedu"/>
当前包 以及 子 包
1.排除方式
<context:component-scan base-package="com.baizhiedu">
<context:exclude-filter type="" expression=""/>
type:assignable:排除特定的类型 不进行扫描
annotation: 排除特定的注解 不进行扫描
aspectj:切入点表达式
包切入点:com.baizhiedu.bean..*
类切入点:*..User
regex:正则表达式
custom:自定义排除策略框架底层开发
</context:component-scan>
排除策略可以叠加使用
<context:component-scan base-package="com.baizhiedu">
<!--排除指定id的注解-->
<context:exclude-filter type="assignable" expression="com.baizhiedu.bean.User"/>
<!--排除指定类型的注解-->
<!--<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>-->
<!--排除指定包下的或者类不去扫描,通过切入点表达式-->
<!-- <context:exclude-filter type="aspectj" expression="com.baizhiedu.injection..*(..)"/>
-->
<context:exclude-filter type="aspectj" expression="*..User"/>
</context:component-scan>
2. 包含方式
4.对于注解开发的思考
- 配置互通
- 什么情况下使用注解 什么情况下使用配置文件
-
搭建环境
-
编码
-
Dao(spring+mybatis)
-
Service(Spring添加事务)
-
Controller (Spring+struts2)
-
第三章。spring 的高级注解(spring3.x及以上)
- 配置bean在应用的过程中 替换了xml具体什么内容呢?
- AnnotationCoinfig ApplicationContext
-
配置Bean开发的细节分析
-
基于注解开发使用日志
1.不能集成Log4j 2.集成logback
- 引入相关的jar包
-
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.3</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.logback-extensions</groupId>
<artifactId>logback-ext-spring</artifactId>
<version>0.1.4</version>
</dependency>
- 引入logback配置文件(logback.xml)
<?xml version="1.0" encoding="UTF-8"?>
<!-- 配置文件修改时重新加载,默认true -->
<configuration >
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder charset="UTF-8">
<!-- 输出日志记录格式 -->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="STDOUT"/>
</root>
</configuration >
- @Configuration注解的本质
3. @Bean注解的基本使用
- 对象的创建
- @Bean注解创建复杂对象的注意事项
ConnectionFactoryBean.java
package com.baizhiedu.bean;
import org.springframework.beans.factory.FactoryBean;
import java.sql.Connection;
import java.sql.DriverManager;
public class ConnectionFactoryBean implements FactoryBean {
@Override
public Object getObject() throws Exception {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/suns?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone = GMT", "root", "123456");
return conn;
}
@Override
public Class<?> getObjectType() {
return Connection.class;
}
@Override
public boolean isSingleton() {
return false;
}
}
AppConfig.java(此处是加了@Configuration注解的类,相当于,applicationContext.xml)
package com.baizhiedu;
import ch.qos.logback.core.db.DriverManagerConnectionSource;
import com.baizhiedu.bean.ConnectionFactoryBean;
import com.baizhiedu.bean.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.sql.Connection;
import java.sql.DriverManager;
@Configuration
public class AppConfig {
@Bean
public User user(){
return new User();
}
@Bean
public Connection conn(){
Connection conn=null;
try{
Class.forName("com.mysql.cj.jdbc.Driver");
conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/suns?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone = GMT", "root", "123456");
}catch (Exception e){
e.printStackTrace();
}
return conn;
}
@Bean
//复杂对象Connection已经在ConnectionFactoryBean中创建好,所以此处是创建的简单对象,对
//复杂对象的调用
public Connection conn1(){
Connection conn=null;
try {
ConnectionFactoryBean factoryBean = new ConnectionFactoryBean();
conn = (Connection) factoryBean.getObject();
}catch (Exception e){
e.printStackTrace();
}
return conn;
}
}
- 自定义id值
- 控制对象的创建次数
- 用户自定义类型
@Configuration
public class AppConfig1 {
@Bean
public UserDAo userDAo() {
return new UserDAoImpl();
}
@Bean("u")
public UserService userService(UserDAo userDAo) {
UserServiceImpl userService = new UserServiceImpl();
userService.setUserDAo(userDAo);
return userService;
}
}
//方法二(简化写法)
@Bean
public UserService userService(){
UserServiceImpl userService = new UserServiceImpl();
userService.setUserDAo(userDAo());
return userService;
- JDK类型的注入(与自定义类型的区别是一个要定义形参,一个不用定义)
package com.baizhiedu.bean;
public class Customer {
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
- jdk类型注入的细节分析
如果直接在代码中进行set方法的注入,会存在偶和
@Configuration
@PropertySource("classpath:/init.properties")
public class AppConfig1 {
@Value("${id}")
private Integer id;
@Value("${name}")
private String name;
@Bean
public UserDAo userDAo() {
return new UserDAoImpl();
}
@Bean
public Customer customer(){
Customer customer = new Customer();
customer.setId(id);
customer.setName(name);
return customer;
}
- @ComponentScan注解
-
基本使用
@Configuration
@ComponentScan(basePackages = “com.baizhiedu.scan”)
public class AppConfig3 {
}等同于
<context:component-scan base-package=""/> -
#####排除,包含的使用
- 排除
单排除
多排除的同时使用
@Configuration
@ComponentScan(basePackages = "com.baizhiedu.scan",
excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Service.class}),
@ComponentScan.Filter(type =FilterType.ASPECTJ,pattern = "*..User1")})
public class AppConfig3 {
}
- 包含
@Configuration
@ComponentScan(
basePackages = "com.baizhiedu.scan",
useDefaultFilters = false,
includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Service.class})}
)
public class AppConfig3 {
}
4. Spring工厂创建对象的多种配置方式
-
多种配置方式的应用场景
-
配置文件的优先级
appliacationContext.xml 为了解耦合不在AppConfig5中使用
而改到AppConfig6中去添加这个注解,其实得到的效果和在 AppConfig5中添加起到的效果一样,但是前者起到了 解饿偶和的作用
@Configuration
//@ImportResource("applicationContext.xml")
public class AppConfig5 {
@Bean
public UserDAo userDAo(){
return new UserDAoImpl();
}
}
@Configuration
@ImportResource("applicationContext.xml")
public class AppConfig6 {
}
@Test
public void test8(){
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig5.class,AppConfig6.class);
UserDAo userDAo = ctx.getBean("userDAo", UserDAo.class);
userDAo.save();
}
applicationContext.xml
只需写一个bean标签覆盖并且别创建新的实现类
<bean id="userDAo" class="com.baizhiedu.injection.UserDAoImplNew"/>
5. 整合多个配置信息
- 为什么会有多个配置信息
-
多配置信息的整合方式
- 多个配置Bean的整合
- 配置Bean与@Component相关注解的整合
- 配置Bean与SpringXML配置文件的整合
-
整合多种配置需要关注哪些要点?
- 如何使用配置的信息 汇总成一个整体
- 如何实现夸配置的注入
1. 多个配置bean的整合
-
多配置的信息汇总
- base-package进行多个配置bean的整合
-
@import
1.可以创建对象 2.多配置bean的整合
- 在工厂创建时,指定多个配置Bean的Class对象
-
夸配置进行注入(讲另一个配置文件的bean注入到当下的配置文件中来)
@Configuration
@Import(AppConfig2.class)
public class AppConfig1 {
@Autowired
private UserDAo userDAo;
@Bean
public UserService userService(){
UserService userService = new UserServiceImpl();
((UserServiceImpl) userService).setUserDAo(userDAo);
return userService;
}
}
@Configuration
public class AppConfig2 {
@Bean
public UserDAo userDAo(){
UserDAo userDAo = new UserDAoImpl();
return userDAo;
}
}
2.配置Bean与@Component相关注解的整合
3. 配置Bean与配置文件整合
6,。配置Bean底层实现原理
7.思维一体的开发思想
1.什么是四维一体
2. 四维一体是的开发案例
3.
8.纯注解版AOP编程
1.搭建环境
1.应用配置Bean
2.注解扫描
2.开发步奏
3.注解Aop细节分析
1.代理创建方式的切换 jdk cglib
<aop:aspectj-autoproxy proxy-target-class=true|false/>
@EnableAspectAutoProxy(proxyTargetClass)
2. springBoot Aop的开发方式
@EnableAspectAutoProxy 已经设置好了
//1.原始对象
@Service
public class UserServiceImpl implements UserService {
@Override
public void register() {
System.out.println("UserServiceImpl.register");
}
@Override
public void login() {
System.out.println("UserServiceImpl.login");
}
}
//2.创建切面 (额外功能 切入点 组装切面)
@Aspect
@Component
public class MyApsect {
@Pointcut("execution(* com.baizhiedu.aop..*.*(..))")
public void pointCut(){}
@Around("pointCut()")
public Object arround(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("------log-----");
Object proceed = joinPoint.proceed();
return proceed;
}
}
spring Aop 代理默认实现是jdk spring Boot 代理默认实现Cglib
9. 纯注解版Spring+mybaitis
- 基础配置(配置Bean)
```bash
1. 链接池
<!--链接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
<property name="url" value="root"></property>
<property name="username" value="root"></property>
</bean>
@Bean
public DruidDataSource dataSource(){
DruidDataSource dataSource=new DruidDataSource();
dataSource.setDriverClassName("");
datasource.setUrl();
....
return dataSource;
}
2. SqlSeesionFactoryBean
<!--创建SqlSessionFactory SqlSessionFactoryBean-->
<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="typeAliasesPackage" value="com.baizhiedu.entity"/>
<property name="mapperLocations">
<list>
<value>classpath:com.baizhiedu.mapper/*Mapper.xml</value>
</list>
</property>
</bean>
@Bean
public SqlSessionFactoryBean(DataSource dataSource){
SqlSwssionFactoryBean sqlSessionFactoryBean=new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
sqlSessionFactoryBean.setTypeAliasesPackage("");
...
return sqlSessionFactoryBean;
}
3. MapperScannerConfigure
<!--创建DAO对象 MapperScannerConfigure-->
<bean id="scanner" class="org.mybatis.spring.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName"value="com.baizhiedu.dao"></property>
</bean>
@MapperScan(basePackages={"com.baizhiedu.dao"})---->配置bean中完成
-
编码
- 实体
- 表
- DAO接口
- Mapper文件
1. MapperLocations编码时通配的写法
//设置Mapper文件的路径
sqlSessionFactoryBean.setMapperLocations(Resource..);
Resource resource=new ClassPathResouce("UserDAOMapper.xml")
sqlSessionFactoryBean.setMapperLocations(new ClassPathResource("UserDAoMapper.xml"));
<property name="mapperLocations">
<list>
<value>classpath:com.baizhiedu.mapper/*Mapper.xml</value>
</list>
</property>
一组mapper文件
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource[] resources = resolver.getResources("com.baizhiedu.mapper/*Mapper.xml");
sqlSessionFactoryBean.setMapperLocations(resources);
2.配置Bean数据偶和问题
mybatis.driverClassName=com.mysql.cj.jdbc.Driver
mybatis.url=jdbc:mysql://localhost:3306/suns?useSSl=false&serverTimezone=UTC
mybatis.username=root
mybatis.password=123456
mybatis.typeAliasesPackages=com.baizhiedu.mapper/*Mapper.xml
@Component
@PropertySource("classpath:mybatis.properties")
public class MybatisProperties {
@Value("${mybatis.driverClassName}")
private String driverClassName;
@Value("${mybatis.url}")
private String url;
@Value("${mybatis.username}")
private String username;
@Value("${mybatis.password}")
private String password;
@Value("${mybatis.typeAliasesPackages}")
private String typeAliasesPackages;
@Value("${mybatis.mapperLocations}")
private String mapperLocations;
@Configuration
@ComponentScan(basePackages = "com.baizhiedu.mybatis")
@MapperScan(basePackages = "com.baizhiedu.mybatis")
public class MybatisAutoConfiguration {
@Autowired
private MybatisProperties mybatisProperties;
@Bean
public DataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(mybatisProperties.getDriverClassName());
dataSource.setUrl(mybatisProperties.getUrl());
dataSource.setUsername(mybatisProperties.getUsername());
dataSource.setPassword(mybatisProperties.getPassword());
return dataSource;
}
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DruidDataSource dataSource) {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
sqlSessionFactoryBean.setTypeAliasesPackage(mybatisProperties.getTypeAliasesPackage());
// sqlSessionFactoryBean.setMapperLocations(new ClassPathResource("UserDAoMapper.xml"));
try{ PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource[] resources = resolver.getResources(mybatisProperties.getMapperLocations());
sqlSessionFactoryBean.setMapperLocations(resources);}
catch (Exception e){
e.printStackTrace();
}
return sqlSessionFactoryBean;
}
}
###### 10.纯注解版事务编程
1. AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext("com.baizhiedu.mybatis");
SpringBoo实现思想
2. SpringMybatis--->Dao 事务基于注解 ---》Service Controller
org.springframework.web.context.ContextLoaderListender--->XML工厂 无法提供 new AnnotationConfigApplicationContext
11. spring 框架中yml的使用
-
什么是yml
YML(YAML)是一种新形势的配置文件,比xml更加简单,比Properties更加强大
-
Properties进行配置问题
1. Properties表达过于繁琐,无法表达数据的内在联系 2. Properties 无法表达对象 集合类型
-
YML语法简介
1. 定义yml文件 xxx.yml xxx.yaml 2. 语法 1. 基本语法 name:suns password:123456 2. 对象概念 account: id:1 password:123456 3. 定义集合 service: - 1111 - 2222
-
Spring与yml集成思路的分析
1. 准备yml配置文件 init.yml name:suns proword:123456 2. 读取yml 转换成Properties YamlPropertiesFactoryBean.setResources( yml配置文件的路径) new ClassPathResource(); YamlPropertiesFactoryBean.getObject()---->Properties 3. 应用PropertySourcesPlaceholderConfigure PropertySourcesPlaceholderConfigure.setProperties(); 4. 类中 @Value注解 注入
-
Spring与YML集成编码
-
环境搭建
<dependency> <groupId>org.yaml</groupId> <artifactId>snakeyaml</artifactId> <version>1.26</version> </dependency> 最低版本1.18
-
编码
1. 准备yml配置文件
2. 配置Bean中操作 完成yaml读取与 PropertySourceplaceholderConfigure的创建
package com.baizhiedu.yml;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;
import java.util.Properties;
@Component
@ComponentScan(basePackages="com.baizhiedu.yml")
public class YmlAutoConfiguration{
@Bean
public PropertySourcesPlaceholderConfigurer configurer(){
YamlPropertiesFactoryBean yamlPropertiesFactoryBean = new YamlPropertiesFactoryBean();
yamlPropertiesFactoryBean.setResources(new ClassPathResource("init.yml"));
Properties properties = yamlPropertiesFactoryBean.getObject();
PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
configurer.setProperties(properties);
return configurer;
}
}
/**
* 用于测试Yml
*/
@Test
public void test3(){
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(YmlAutoConfiguration.class);
Account account = (Account)ctx.getBean("account");
System.out.println("account.getname"+account.getName());
System.out.println("account.getPassword()"+account.getPassword());
}
3. 类 加入@Value注解
6. Spring 与YMl集合处理的问题
1. 集合处理的问题
因为使用YamlPropertiesFactoryBean解析yml文件,但是它解析不了list类型的数据
所以yml中list赋值时采用
list: 111,222
而不是采用传统的
list:
- 1111
- 2222
实体类中的注解
Spring采用El表达式解决
采用 @Value("#{'${list}'.split(',')}")
不用传统的@Value("${list}")
2. 对象类型的YAMl进行配置时 过于繁琐
@Value("${account.name}")
SpringBoot @ConfigurationProperties