Spring从入门到精通
第一章 Spring基础
1.环境搭建
导入Pom
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>
附属下载的内容
2. 配置文件
1、配置文件的放置位置:任意位置即可。
2、配置文件的命名:没有硬性要求,建议为applicationContext.xml
注意在以后的编码过程中,需要对配置文件路径进行设置
2.1.配置文件创建
3. Spring的核心API
3.1 applicationContext
- ApplicationContext
作用:Spring提供的ApplicationContext这个工厂,用于对象的创建
好处:解耦合 - ApplicationContext为接口类型
接口的作用:屏蔽实现的差异
非web环境:ClassPathXmlApplicationContext(main方法中,或者junit)
web环境:XmlWebApplicationContext
非web环境
3.2 applicationContext
ApplicationContext工厂的对象占用大量的内存
不会频繁创建对象,一个应用之后创建一个工厂对象。
applicationContext这种工厂一定是线程安全的。
4.Spring第一个程序
步骤:
1、创建类型
2、配置文件的配置 applicationContext.xml
<!--id起个名字,唯一;class配置全限定名-->
<bean id="person" class="com.xiaohe.Person"></bean>
3、通过工厂类,获取对象
@Test
public void test(){
//获取Spring工厂
/**
* ClassPathXmlApplicationContext参数表示配置文件的路径
* */
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("/applicationContext.xml");
//根据工厂获取对象
/**
* getBean参数表示配置文件bean下的id名字
* */
Person person = (Person) applicationContext.getBean("person");
System.out.println(person);
}
}
细节分析
- 名称解释
Spring工厂创建的对象,叫做bean或者组件(Compont)
- spring工厂相关的方法
@Test
public void test1(){
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
//Person person=applicationContext.getBean("person",Person.class);
//System.out.println(person);
//当前Spring配置文件中,只能有一个<bean class是Person类型>
Person person=applicationContext.getBean(Person.class);
System.out.println(person);
//获取的是Spring工厂配置文件所有配置的ID值
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println("beanDefinitionNames="+beanDefinitionName);
}
//根据类型获取spring工厂配置文件的id值
String[] beanNamesForType = applicationContext.getBeanNamesForType(Person.class);
for (String s : beanNamesForType) {
System.out.println("--->"+s);
}
//用于判断配置文件是否存在指定id值的bean
boolean isExist = applicationContext.containsBeanDefinition("person");
System.out.println(isExist);
//用于判断配置文件是否存在指定id值的bean
boolean isExist= applicationContext.containsBean("person");
System.out.println(isExist);
}
spring配置文件需要注意的细节
在spring配置文件中只写class,不写id
<bean class="com.xiaohe.Person"/>
测试
@Test
public void test2(){
//创建ApplicationContext对象
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("/applicationContext.xml");
/*Person bean = applicationContext.getBean(Person.class);
System.out.println("--->"+bean);*/
String[] beans = applicationContext.getBeanDefinitionNames();
for (String bean : beans) {
System.out.println("----》"+bean);
}
}
结果
Spring配置文件的name属性
作用:用于在spring的配置文件中,为bean对象定义别名
id与name(别名)的相同点与不同点
相同:
1、applicationContext.getBean(“id/name”);
2、<bean name="" class="" 等效于<bean name="" class=""
不同:
1、别名可以定义多个,中间用逗号隔开
2、xml 的id属性值命名时要求:必须要以id开头,name属性的值,命名没有要求。
5.spring工厂的底层原理(简易版)
第二章 spring与日志框架的整合
spring与日志框架的整合,日志可以在控制台进行打印,输出一些重要的信息。
默认:spring默认整合logback,log4j2
Spring整合log4j过程
1、引入log4j jar包
2、引入log4j.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 # 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-ddHH:mm:ss} %-5p %c{1}:%L - %m%n
第三章 注入
1.什么是注入
通过Spring工厂及配置文件,为所创建的对象的成员变量赋值。
1.1为什么要注入
1.2如何进行注入
- 1.类为成员变量提供set/get方法
- 2.配置spring的配置文件
<bean id="person" name="p" class="com.xiaohe.Person" >
<property name="name">
<value>和振斌</value>
</property>
<property name="age">
<value>20</value>
</property>
</bean>
- 测试
/**
* 测试注入
* */
@Test
public void test5(){
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("/applicationContext.xml");
Person person = (Person) applicationContext.getBean("person");
System.out.println("person:"+person);
}
1.3注入的好处
解耦合
1.4Spring注入原理分析(简易版)
Set注入和构造注入
第三章 控制反转与依赖注入
1、控制反转(IOC)
1、控制:对于成员变量赋值的控制权
2、反转控制:把对于成员变量赋值的控制权,从代码中反转到spring工厂和配置文件中去。
3、底层实现:工厂设计模式
实现图
依赖注入(Dependency Injection DI)
注入:通过Spring的工厂及其配置文件,为对象的成员变量赋值
依赖注入:当一个类需要另一个类时,就意味着依赖,一旦出现依赖,就可以把另一个类作为本类的成员变量,最终通过Spring配置文件进行注入
好处:解构
2、Spring工厂创建复杂对象的三种方式
步骤
- 1、实现FactoryBean接口
public class ConnectionFactory implements FactoryBean<Connection> {
//用于书写创建复杂对象的代码
public Connection getObject() throws Exception {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/test","root","123456");
return conn;
}
public Class<?> getObjectType() {
return Connection.class;
}
public boolean isSingleton() {
return false;
}
}
- 2、Spring配置文件的配置
<bean id="conn" class="com.xiaohe.factoryBean.ConnectionFactory"/>
2.2、实例工厂
1、避免spring的侵入
2、整合遗留问题
开发步骤
<bean id="connFactory"class="com.baizhiedu.factorybean.ConnectionFactory"></bean>
<bean id="conn" factorybean="connFactory"factorymethod="getConnection"/>
实例工厂
<bean id="conn" class="com.xiaohe.factoryBean.ConnectionFactory" factory-method="getConnection"/>
1.3Spring工厂总结
第四章 控制Spring工厂创建对象的次数
1、简单工厂创建次数
<bean id="accont" scope="singleton | prototype" class="xxx.Account"
singleton:只创建一次
prototype:创建多次
2、为什么要控制对象的创建次数
好处:节省内存
生命周期
第五章 后置处理Bean
1、BeanPostProcessor作用:对于Spring工厂所创建的对象,进行再加工
我们实现BeanPostProcessor规定的接口的方法
Object postProcessBeforeInitiallization(Object bean,String beanName)
作用:Spring在创建完对象,并进行注入后,可以运行Before方法进行加工
获得Spring创建好的对象,通过方法的参数
最终通过返回值交给Spring框架
Object postProcessAfterInitallization(Object bean,Strinng beanName)
作用:Spring在执行完对象的初始化操作后,可以运行After方法进行加工
获得Spring创建好的对象,通过方法的参数
最终通过返回值交给Spring框架
- BeanPostProcessor开发步骤
1、类实现BeanPostProcessor接口public class MyBeanPostProcessor implements BeanPostProcessor { public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("实现了postProcessBeforeInitialization"); return bean; } public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { Categroy categroy= (Categroy) bean; categroy.setName("hzb cool"); return categroy; }
- spring配置文件配置
<bean id="c" class="com.xiaohe.BeanPost.Categroy">
<property name="id" value="10"/>
<property name="name" value="hzb"/>
</bean>
<bean id="myBeanPostProcessor" class="com.xiaohe.BeanPost.MyBeanPostProcessor"/>
运行效果
- 注意BeanPostProcessor会对工厂所有对象进行加工。
第六章 AOP编程
1、静态代理设计模式
为什么需要代理设计模式?
2、代理设计模式
2.1 概念
通过代理类,为原始类增加额外的功能
好处:利于原始类的维护
2.2 编码
静态代理:为每一个原始类,手工编写一个类
public class UserServiceProxy implements UserService {
//原始对象
private UserServiceImpl userService=new UserServiceImpl();
public void register(User user) {
System.out.println("日志的额外功能");
userService.register(user);
}
public boolean login(String name, String password) {
System.out.println("日志的额外功能");
return userService.login(name,password);
}
}
2.3 静态代理存在的问题
1、静态类文件数量过多,不利于项目管理
UserServiceImpl ----------UserServiceProxy
OrderServiceImpl---------OrderServiceProxy
2、额外功能维护性差
3、Spring的动态代理
3.1 概念
通过动态代理类为原始类增加额外功能
3.2搭建环境
导入pom
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.5</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
3.3 开发步骤
1.第一步:创建原始对象
public class UserServiceImpl implements UserService {
public void register(User user) {
System.out.println("执行业务运算+DAO");
}
public boolean login(String name, String password) {
System.out.println("执行了登录方法");
return false;
}
}
第二步:创建userService对象
<bean id="userService" class="com.xiaohe.proxy.OrderServiceImpl"/>
额外功能开发 Spring提供了MethodBeforceAdvice接口
第三步: 额外功能
public class Before implements MethodBeforeAdvice {
/**
* 作用: 需要运行在原始方法执行之前运行额外功能,书写在before方法中
* */
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("----method before advice log");
}
}
<bean id="before" class="com.xiaohe.dynamic.Before"/>
第四步:定义切入点
切入点:额外功能加入的位置
目的:由程序员根据自己需求,决定额外功能加入给哪个原始方法
第五步 简单的测试:让所有的文件
在配置里面写
<aop:config>
<!--切入点-->
<!--expression切入点表达式 表示所有的方法都是切入点-->
<aop:pointcut id="pc" expression="execution(* *(..))"/>
</aop:config>
组装
<!--组装-->
<aop:advisor advice-ref="before" pointcut-ref="pc"/>
调用
目的:获取Spring工厂创建的动态代理的对象,并进行调用
注意
1、Spring的工厂通过原始对象的id值获得的是代理对象
ctx.getBean(“userService”);
2、获得的代理对象后,可以通过声明接口类型,进行对象的存储
4、动态代理的好处
好处一、
在额外功能不改变的过程中,创建其他目标类的对象时,只需要指定原始对象即可。
好处二、
动态代理额外功能的维护性大大增强。
5、动态代理详解
四步骤
5.1、Spring动态代理详解
- MethodBeforeAdvice分析
1、MethodBeforeAdvice接口的作用:额外功能运行在原始方法之前,进行额外功能操作。
public class Before implements MethodBeforeAdvice {
/**
* 作用: 需要运行在原始方法执行之前运行额外功能,书写在before方法中
* method表示:额外功能所增加给的那个原始方法
* Object[]:额外功能增加给那个原始方法的参数
* Object:原始对象
* */
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("----method before advice log");
}
}
2、Before方法的三个参数在实战中,该如何使用:
before方法的参数,在实战中,会根据需要进行使用,不一定都会用到,也可能用不到。
- MethodInterceptor(方法拦截器)
/**
* 拦截器
* invoke方法的作用:额外功能写在invoke
* 额外方法 原始方法之前
* 原始方法之后
* 原始方法之前 之后
* 参数:MethodInvocation 表示额外功能所增加的那个原始方法
* */
public class Arround implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("------前--------");
//原始方法运行
Object ret = invocation.proceed();
System.out.println("------后---------");
return ret;
}
}
MethodBeforeAdvice只能运行在原始方法之前
5.2、切入点详解
<aop:pointcut id="pc" expression="execution(* *(..))"/>
切入点表达式:
execution()切入点函数
* *(…)
第一个 *表示修饰符和返回值
第二个 *表示方法名
第三个 …表示参数
精准方法切入点表示方法
execution()切入点函数
1、最为重要的切入点函数,功能最全
2、执行方法切入点表达式类切入点表达式包切入点函数
弊端:书写麻烦
args
作用:主要用于函数方法参数的匹配
切入点:方法参数必须是两个字符串类型的参数
within
主要用于进行类、包切入点表达式的匹配
切入点:UserServiceImpl这个类
execution(* *.userServiceImpl.*(..))
within(*..UserServiceImpl)