初始Spring
目录
一、Spring
(1) 核心思想
(1) spring体系结构
(2) spring框架模块
(3) spring环境搭建
(4) IOC(Inversion of Control,中文释义:控制反转)
(5) AOP(中文释义:面向切面编程)
二、SpringIOC的使用
1.使用步骤
(1)将类注入,SpringIoC容器(xml配置,注解实现)
(2)加载spring主配置文件获取容器对象
三、SpringDI
1.概念
2.作用
3.实现步骤
4.SpringDI
4.1 set注入基本类型和String
4.2 set注入JavaBean对象(DI三层调用)
4.3 set注入复杂类型
4.4 构造注入基本类型与String
4.5 构造注入 JavaBean对象(三层调用)
四、SpringIOC容器:对Bean的管理
1.bean的创建
(1)通过反射调用类的无参构造方法(默认)
(2)通过指定的工厂,创建bean对象
(3)通过指定的静态工厂,创建bean对象
2.bean的作用域
3.bean的生命周期
1.实例化
2.初始化
3.操作使用
4.销毁
五、spring 的配置
spring2.5后 ==xml+annotation
1.注入类
2.注入数据
3.其他注解
spring3.0后 ==annotation+JavaConfig
六、Spring遵循的原则以及设计模式
1、Spring 遵循的核心设计原则
(1). 依赖注入原则(Dependency Injection, DI)
(2). 控制反转原则(Inversion of Control, IoC)
(3). 面向接口编程原则
(4). 单一职责原则(Single Responsibility Principle)
(5). 开闭原则(Open-Closed Principle)
(6). 里氏替换原则(Liskov Substitution Principle)
(7). 迪米特法则(Law of Demeter)
2、Spring 中常用的设计模式
(1). 工厂模式(Factory Pattern)
(2). 单例模式(Singleton Pattern)
(3). 模板方法模式(Template Method Pattern)
(4). 代理模式(Proxy Pattern)
七、Spring AOP
1、AOP概念及作用
(1).概念
(2).作用
2、Spring AOP的实现
3、AOP通知
4、AOP配置
(1).AOP连接点(Join point)
(2).AOP切点(Pointcut)
(3).AOP目标对象(Target)
(4).AOP织入(Weaving)
(5).AOP切面:切点+通知
(6).SpringAOP+AspectJ实现步骤
5、切点表达式配置语法
(1).修饰符可以省略代表任意
(2).返回值可以使用“*”代表任意
(3).包名可以使用“*”代表任意名称
(4).包名可以使用“..”代表任意个数
(5).类名与方法名可以使用“*”代表任意
(6).参数列表可以使用".."代表任意个数任意类型
八、循环依赖
九、常用的Aware接口
一、Spring
(1) 核心思想
Spring是一个轻量级、开源的Java企业级应用(指的是大规模、性能和安全要求高、业务复杂、灵活多变的大型WEB应用程序)开发框架,核心价值是通过依赖注入(DI)和面向切面编程(AOP)降低代码耦合度,简化开发流程,同时提供丰富的模块支持(如Web、数据访问、事务管理等)。也就是对象管理和功能增强的容器。
(1) spring体系结构
(2) spring框架模块
(1)Spring Core :Spring框架的最基础部分,提供DI特性。
(2)Spring Context:Spring上下文,提供Bean容器的集合。
(3)Spring AOP:基于Spring Core的符合规范的切面编程的实现。
(4)Spring JDBC:提供了JDBC的抽象层,简化了JDBC编码。
(5)Spring ORM:对于主流ORM框架(Hibernate、Toplink等)进行集成。
(6)Spring Web:为Spring在Web应用程序中的使用提供了支持。
(3) spring环境搭建
1.坐标(依赖)
2.主配置文件(beans.xml)
(4) IOC(Inversion of Control,中文释义:控制反转)
将对象的创建、依赖管理等“控制权”从代码中转移到Spring容器,开发者无需手动new对象,而是由容器统一创建和注入,极大降低耦合。
(5) AOP(中文释义:面向切面编程)
将日志、事务、权限校验等“通用功能”从业务代码中剥离,单独定义为“切面”,在不修改业务代码的前提下,通过配置将通用功能织入到指定业务流程中,提升代码复用性。
二、SpringIOC的使用
由Spring框架根据配置文件或注解等方式,创建bean对象并管理各个bean对象之间的依赖关系,使对象之间形成松散耦合的关系,实现解耦。
控制:指的是对象创建(实例化、管理)的权利。
反转:控制权交给外部环境(Spring框架,IoC容器)。
1.使用步骤
(1)将类注入,SpringIoC容器(xml配置,注解实现)
<bean id="唯一标识" class="实现类的完全限定名称"></bean>
(2)加载spring主配置文件获取容器对象
实现类:
ClassPathXmlApplicationContext:通过加载配置文件的相对路径获取容器对象。 FileSystemXmlApplicationContext:通过加载配置文件的绝对路径获取容器对象。 AnnotationConfigApplicationContext:加载配置类。
接口:
ApplicationContext(子接口)
BeanFactory(父接口)
三、SpringDI
1.概念
DI(Dependecy Inject,中文释义:依赖注入) 是对IOC概念的不同角度的描述,是指应用程序在运行时,每一个bean对象都依赖IOC容器注入当前bean对象所需要的另外一个bean对象。
2.作用
胶水,帮助springIOC容器,把有依赖关系的javaBean对象粘合在一起。
3.实现步骤
(1)提供属性方法提供set方法。
(2)配置标签set注入:<property 属性名="属性值"></property>
4.SpringDI
实现方式:
(1)set注入 (2)构造注入 (3)属性注入 (4)注解注入
数据类型:
(1)基本类型与String
(2)JavaBean对象注入(三层调用)
(3)复杂类型(构造注入不支持 )
4.1 set注入基本类型和String
//teacher实体类
public class Teacher {private String tname;private int tage;private String tsex;//省略getter,setter、toString方法
}
//注入到xml文件中
<bean id="teacher" class="com.ape.pojo.Teacher"><property name="tname" value="王老师"></property><property name="tage" value="30"></property><property name="tsex" value="男"></property>
</bean>
//属性:name==>属性名、value==>属性值、ref==>属性值的引用。
//测试类
public class Test03 {public static void main(String[] args) {//加载相对路径ApplicationContext applicationContext =new ClassPathXmlApplicationContext("beans.xml");//通过Spring创建对象并加载XML文件Teacher teacher=(Teacher) applicationContext.getBean("teacher");System.out.println(teacher);}
4.2 set注入JavaBean对象(DI三层调用)
//dao层接口与实现类
//分开写的
public interface IUserDao {public void save();
}public class UserDaoImp implements IUserDao{@Overridepublic void save() {System.out.println("===dao的新增方法===");}
}
//service层接口与实现类
public interface IUserService {public void save();
}public class UserServiceImp implements IUserService{IUserDao dao;//set注入public void setDao(IUserDao dao) {this.dao = dao;}@Overridepublic void save() {System.out.println("===service的新增方法===");dao.save();}
//controller层接口与实现类
public interface IUserController {public void save();
}public class UserControllerImp implements IUserController {IUserService service;//set注入public void setService(IUserService service){this.service=service;}@Overridepublic void save() {System.out.println("===controller的新增方法===");service.save();}
}
//beans.xml
// <!--注入系统时间类-->
// <bean id="date" class="java.util.Date"></bean>
<bean id="daos" class="com.ape.dao.UserDaoImp"></bean>
<bean id="services" class="com.ape.service.UserServiceImp"><property name="dao" ref="daos"></property>
</bean>
<bean id="controllers" class="com.ape.controller.UserControllerImp"><property name="service" ref="services"></property>
</bean>
//测试类
public class Test02 {public static void main(String[] args) {//1.加载spring主配置文件,获取核心对象ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");IUserController controllers= (IUserController) applicationContext.getBean("controllers");controllers.save();
4.3 set注入复杂类型
//实体类
public class Student {private String[] myArray;private List myList;private Set mySet;private Map myMap;private Properties myProperties;//省略getter、setter、toString方法
}
//beans.xml
<bean id="student" class="com.ape.pojo.Student"><property name="myArray"><array><value>英雄联盟</value><value>王者荣耀</value><value>三角洲</value><value>CS1.5</value><value>魔兽争霸</value></array></property><property name="myList"><list><value>字节跳动</value><value>阿里巴巴</value><value>小米</value><value>猿究院</value><value>腾讯</value></list></property><property name="mySet"><set><value>朴彩英</value><value>金智秀</value><value>金珍妮</value><value>权志龙</value><value>Lisa</value></set></property><property name="myMap"><map><entry key="泰国" value="曼谷"></entry><entry key="中国" value="北京"></entry><entry key="缅甸" value="内比都"></entry><entry key="越南" value="河内"></entry><entry key="老挝" value="万象"></entry><entry key="新加坡" value="新加坡"></entry><entry key="马来西亚" value="吉隆坡"></entry></map></property><property name="myProperties"><props><prop key="肉夹馍">10</prop><prop key="凉皮">7</prop><prop key="冰峰">2</prop><prop key="柳巷面">19</prop><prop key="一家星月楼">30</prop></props></property>
</bean>
//测试类
public class Test03 {public static void main(String[] args) {ApplicationContext applicationContext =new ClassPathXmlApplicationContext("beans.xml");Student student=(Student) applicationContext.getBean("student");System.out.println(student);
4.4 构造注入基本类型与String
//实体类
public class Singer {private String sname;private int sage;private String stype;public Singer() {}public Singer(String sname, int sage, String stype) {this.sname = sname;this.sage = sage;this.stype = stype;}@Overridepublic String toString() {return "Singer{" +"sname='" + sname + '\'' +", sage=" + sage +", stype='" + stype + '\'' +'}';}
}
//beans.xml
<!--基本类型与String-->
// 三种调用方式
<bean id="singer1" class="com.ape.pojo.Singer"><constructor-arg name="sname" value="陈之默"></constructor-arg><constructor-arg name="sage" value="25"></constructor-arg><constructor-arg name="stype" value="RB"></constructor-arg>
</bean><bean id="singer2" class="com.ape.pojo.Singer"><constructor-arg type="java.lang.String" value="汪苏泷"></constructor-arg><constructor-arg type="int" value="35"></constructor-arg><constructor-arg type="java.lang.String" value="RB"></constructor-arg>
</bean><bean id="singer3" class="com.ape.pojo.Singer"><constructor-arg index="0" value="任贤齐"></constructor-arg><constructor-arg index="1" value="50"></constructor-arg><constructor-arg index="2" value="RB"></constructor-arg>
</bean>
//测试类
public static void main(String[] args) {ApplicationContext applicationContext=new ClassPathXmlApplicationContext("beans1.xml");Singer singer1=(Singer)applicationContext.getBean("singer1");Singer singer2=(Singer)applicationContext.getBean("singer2");Singer singer3=(Singer)applicationContext.getBean("singer3");System.out.println(singer1);System.out.println(singer2);System.out.println(singer3);
4.5 构造注入 JavaBean对象(三层调用)
//UserServiceImp类
//dao类不变IUserDao dao;
//构造注入
public UserServiceImp() {
}
public UserServiceImp(IUserDao dao) {
this.dao = dao;
}
//UserControllerImp类
IUserService service;
//构造注入
public UserControllerImp() {
}public UserControllerImp(IUserService service) {
this.service = service;
}
//beans1.xml
<!--javaBean对象-->
<bean id="daos1" class="com.ape.dao.UserDaoImp"></bean>
<bean id="service1" class="com.ape.service.UserServiceImp"><constructor-arg name="dao" ref="daos1"></constructor-arg>
</bean>
<bean id="controller1" class="com.ape.controller.UserControllerImp"><constructor-arg name="service" ref="service1"></constructor-arg>
</bean>
//测试类
public class Test05 {public static void main(String[] args) {ApplicationContext applicationContext=new ClassPathXmlApplicationContext("beans1.xml");IUserController controller=(IUserController)applicationContext.getBean("controller1");controller.save();}
}
四、SpringIOC容器:对Bean的管理
1.bean的创建
(1)通过反射调用类的无参构造方法(默认)
//实体类
public class Singers {public Singers() {System.out.println("===执行Singers的无参构造方法===");}
}
//BeanFactory工厂
public class BeanFactory {//声明成员变量static Properties pro=null;//编写静态块做初始化操作static {try {//1.实例化属性对象pro=new Properties();//2.加载静态资源文件InputStream fis=BeanFactory.class.getClassLoader().getResourceAsStream("beans.properties");pro.load(fis);} catch (IOException e) {e.printStackTrace();}}//帮助创建对象public static Object getBean(String key){//1.根据beanName在属性文件中获取对应value值String value=pro.getProperty(key);//2.通过反射实例化对象Object obj=null;try {obj=Class.forName(value).newInstance();} catch (InstantiationException e) {throw new RuntimeException(e);} catch (IllegalAccessException e) {throw new RuntimeException(e);} catch (ClassNotFoundException e) {throw new RuntimeException(e);}return obj;}
}
//beans2.xml
<bean id="singers" class="com.ape.pojo.Singers"></bean>
(2)通过指定的工厂,创建bean对象
//SingersFactory普通工厂
public class SingersFactory {public Singers createSingers(){System.out.println("===执行SingersFactory工厂方法===");return new Singers();}
}
//beans2.xml
<bean id="singers" class="com.ape.pojo.Singers" factory-bean="factory" factory-method="createSingers"></bean>
<bean id="factory" class="com.ape.factory.SingersFactory"></bean>
(3)通过指定的静态工厂,创建bean对象
//SingersStaticFactory静态工厂
public class SingersStaticFactory {//创建对象public static Singers createSingers(){System.out.println("===执行SingersStaticFactory静态工厂方法===");return new Singers();}
}
//beans2.xml
<bean id="singers" class="com.ape.factory.SingersStaticFactory" factory-method="createSingers"></bean>
//测试类
public class Test06 {public static void main(String[] args) {ApplicationContext applicationContext=new ClassPathXmlApplicationContext("beans2.xml");Singers singers=(Singers)applicationContext.getBean("singers");System.out.println(singers);
2.bean的作用域
含义:bean的创建方式
语法:<bean scope="属性值"></bean>
属性值: singleton单例(默认)、 prototype多例、 request请求、session会话。
//eg:将其设为多例,每调用一次就会创建一次对象
<bean id="students" class="com.ape.pojo.Students" scope="prototype"></bean>
3.bean的生命周期
1.实例化
Spring容器在进行实例化时,会将xml或注解配置的信息封装成一个BeanDefinition对象,所有的BeanDefinition存储到一个名为beanDefinitionMap的Map集合中去,Spring框架在对该Map进行遍历,通过Spring的后处理器(Bean工厂后处理器:BeanFactoryPostProcessor有两个子接口(BeanFactoryPostProcessor(注册和修改)/
BeanDefinitionRegistryPostProcessor(注册))、允许我们介入到Bean的整个实例化的过程中来,以达到动态注册BeanDefinition、动态修改BeanDefinition以及动态修改Bean的作用,最后使用反射创建Bean实例对象,生成一个半成品的对象。
2.初始化
将半成品的对象注入对象依赖的属性值、若实现了Aware的相关接口,就执行一些Aware接口的方法、若实现了BeanPostProcess接口,就执行Bean后处理器(BeanPostProcessor)的前置处理(postProcessBeforeInitialization方法),接下来若Bean实现了InitializingBean接口,就调用其afterPropertiesSet()方法,若通过@PostConstruct注解指定了方法,或类中自定义了初始化方法并在XML中配置了init-method,就执行对应方法。最后执行后置处理(postProcessAfterInitialization方法),执行完成后,完整的Bean对象就会被放在singletonObjects中,以供后续使用。
3.操作使用
调用getBean()方法获取Bean对象
4.销毁
调用ClassPathXmlApplicationContext的close()方法触发销毁,若Bean实现了DisposableBean接口,调用其destroy()方法。 若通过@PreDestroy注解指定了方法,或自定义了销毁方法并XML中配置了destroy-method,就执行对应方法。
作用:释放资源(如关闭连接、清理缓存)。
1.实例化
创建对象(无参构造)
2.初始化
2.1接口初始化(实现InitializingBean)
2.2属性初始化(自己创建方法)
3.操作使用
4.销毁
4.1接口销毁了(实现DisposableBean)
4.2属性销毁了(自己创建方法)
销毁前,在测试类中,调用ClassPathXmlApplicationContext实现类的close()方法,才会执行到销毁方法。
//Teachers类
public class Teachers implements InitializingBean, DisposableBean {//实例化public Teachers(){System.out.println("====>生命周期:实例化");}//初始化(接口)@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("====>生命周期:初始化1(接口)");}//销毁(接口)@Overridepublic void destroy() throws Exception {System.out.println("====>生命周期:销毁1(接口)");}//初始化(属性)public void doInit(){System.out.println("====>生命周期:初始化2(属性)");}//销毁(属性)public void doDestroy(){System.out.println("====>生命周期:销毁2(属性)");}
}
//xml
<bean id="teachers" class="com.ape.pojo.Teachers" init-method="doInit" destroy-method="doDestroy"></bean>
//测试类public class Test07 {public static void main(String[] args) {ClassPathXmlApplicationContext applicationContext =new ClassPathXmlApplicationContext("beans2.xml");Teachers teachers = (Teachers)applicationContext.getBean("teachers");System.out.println(teachers);applicationContext.close(); //子类独有的方法}
}
五、spring 的配置
(1)spring2.5前 ==xml
(2)spring2.5后 ==xml+annotation
(3)spring3.0后 ==annotation+JavaConfig配置类
spring2.5后 ==xml+annotation
目的优化一下代码: <bean id="" class="" init-method="" destroy-method="" scope="" autowire=""> <property></property> <constructor-arg></constructor-arg> </bean>
注解:
1.注入类
替换:<bean id="" class=""></bean>
位置:类
语法:@Component(value="注入容器中的id,如果省略id则为类名且首字母小写,value属性名称可以省略")
举例: <bean id="user" class="com.apesource.包.User"></bean> || 等价于 ||
@Component
Class User{}
注意: 不能单独用,配合扫描使用<context:component-scan base-package=""> </context:component-scan>
@Repository===== 注入数据访问层
@Service======= 注入业务层
@Controller==== 注入控制层
以上三个注解与@Component功能语法一致
2.注入数据
@Value
含义:注入基本数据与String
替换:<property></property>
修饰:成员变量
语法:@Value("数据内容") @Value("${动态获取}")
注意: 不能单独使用,配合加载配置文件标签 <context:property-placeholder location="classpath:message.properties"></context:property-placeholder>
@Autowired
语法:@Autowired(required="true-默认、false、是否必须进行装配")
修饰:成员变量
含义:注入javaBean
注意:
1.默认是按照类型装配,如果容器中有多个类型,则会自动切换为名称装配
2.默认是按照类型装配,如果容器中有多个类型,则会自动切换为名称装配,若名称也没有与之对应的则会报异常 NoUniqueBeanDefinitionException
3.默认是按照类型装配 ,如果容器中没有一个类可以与之匹配,则会报异常NoSuchBeanDefinitionException
3.其他注解
@Primary
含义:首选项,当类型冲突的情况下,此注解修饰的类被列为首选(备胎扶正)
修饰:类
注意:不能单独使用,必须与@Component....联合使用
@Qualifier(value="名称") spring提供
含义:按照名称装配
修饰:成员变量
注意:不能单独使用,必须与@Autowired联合使用
@Resource(name="名称") jdk提供
含义:按照名称装配
修饰:成员变量
注意:单独使用
@Scope
含义:配置类的作用域
修饰:类
注意:不能单独使用,必须与@Component....联合使用
@Scope("prototype") @Scope("singleton") @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
@PostConstruct:初始化,替换init-method
@PreDestroy:销毁,替换destory-method
spring3.0后 ==annotation+JavaConfig
配置类 此类充当配置类,替代applicationContext.xml文件
@Configuration
作用:指定当前类是一个配置类
细节:当配置类作为AnnotationConfigApplicationContext对象创建的参数时,该注解可以不写。
@ComponentScan
作用:用于通过注解指定spring在创建容器其时要扫描的包
替换:<context:component-scan base-package=""></context:component-scan>
@PropertySource
作用:用于指定properties文件的位置
替换:<context:property-placeholder location=""></context:property-placeholder>
六、Spring遵循的原则以及设计模式
1、Spring 遵循的核心设计原则
(1). 依赖注入原则(Dependency Injection, DI)
核心思想:组件不主动创建依赖对象,而是通过外部容器(Spring)注入依赖,降低组件间耦合。
体现:通过@Autowired
、构造器注入等方式,让对象的依赖由容器管理,而非自身硬编码。
(2). 控制反转原则(Inversion of Control, IoC)
核心思想:将对象的创建、管理权从业务代码转移到 Spring 容器,反转了传统的 "主动创建依赖" 的流程。
体现:容器负责 Bean 的生命周期(实例化、注入、销毁),开发者专注于业务逻辑。
(3). 面向接口编程原则
核心思想:依赖抽象(接口)而非具体实现,提高代码的可替换性和扩展性。
体现:Spring 中的BeanFactory
与ApplicationContext
、Resource
接口及其实现类等,均通过接口定义规范,具体实现可灵活替换。
(4). 单一职责原则(Single Responsibility Principle)
核心思想:一个类只负责一项职责,降低耦合度和维护成本。
体现:BeanFactory
专注于 Bean 的创建,ApplicationContext
扩展上下文功能,TransactionManager
专注于事务管理等。
(5). 开闭原则(Open-Closed Principle)
核心思想:对扩展开放,对修改关闭,通过抽象和接口实现灵活扩展。
体现:通过BeanPostProcessor
、FactoryBean
等扩展点,无需修改 Spring 源码即可增强功能(如自定义 Bean 初始化逻辑)。
(6). 里氏替换原则(Liskov Substitution Principle)
核心思想:子类可替换父类且不改变原有功能逻辑。
体现:Spring 中各种接口的实现类(如ArrayList
实现List
)可无缝替换,不影响依赖该接口的代码。
(7). 迪米特法则(Law of Demeter)
核心思想:一个对象应尽可能少地了解其他对象,降低耦合。
体现:通过 Spring 容器作为中间层,组件无需直接交互,而是通过容器间接获取依赖,减少彼此的了解。
2、Spring 中常用的设计模式
(1). 工厂模式(Factory Pattern)
应用:BeanFactory
和ApplicationContext
是典型的工厂模式实现,负责创建和管理 Bean 对象。
示例:BeanFactory.getBean(String name)
通过名称获取 Bean,隐藏了对象创建的细节。
(2). 单例模式(Singleton Pattern)
应用:Spring 默认的 Bean 作用域为单例(singleton
),容器中只会创建一个实例并复用。
实现:通过singletonObjects
缓存单例 Bean,保证全局唯一(非绝对线程安全,需用户自行处理并发)。
(3). 模板方法模式(Template Method Pattern)
应用:定义算法骨架,将可变步骤延迟到子类实现,减少重复代码。
示例:JdbcTemplate
封装了 JDBC 的固定流程(连接、关闭资源),用户只需提供SQL
和结果映射逻辑。
(4). 代理模式(Proxy Pattern)
应用:AOP(面向切面编程)的核心实现,通过动态代理增强目标方法(如事务、日志、权限控制)。
类型:JDK 动态代理:基于接口的代理(如Proxy
类)。
CGLIB代理:基于类的继承代理(适用于无接口的类)。
七、Spring AOP
1、AOP概念及作用
(1).概念
AOP(Aspect-Oriented Programming: 面向切面编程):将那些与业务无关,却为业务模块所共同调用的逻辑(例如事务处理、日志管理、权限控制等)封装抽取成一个可重用的模块,这个模块被命名为“切面”(Aspect),便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。
(2).作用
AOP 是 OOP 的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。(提高代码复用率以及解耦)
2、Spring AOP的实现
Spring AOP 基于动态代理实现:
(1).如果被代理的对象,已经实现某个接口,则 Spring AOP 会使用 JDK Proxy(反射),基于接口的方式,创建代理对象(JDK动态代理的核心是InvocationHandler接口和Proxy类);
(2).如果被代理的对象,没有实现某个接口,就无法使用 JDK Proxy 去进行代理了,这时候 Spring AOP 会使用 Cglib,基于继承的方式,生成一个被代理对象的子类来作为代理(Cglib动态代理的核心是MethodInterceptor接口和Enhancer类);
3、AOP通知
AOP将抽取出来的共性功能称为通知;通知类型:以通知在上下文中的具体位置作为划分。
解释:通知就是需要增强的方法的方法内容以及执行位置的结合。
- 前置通知(Before)--执行前
- 返回通知(After-returning)--执行完成后
- 异常通知(After-throwing)--执行有错误
- 后置通知(After)--不管如何都要执行的
- 环绕通知(Around)--替换上面四个的
4、AOP配置
(1).AOP连接点(Join point)
AOP将所有的方法都视为连接点,不管是接口里面的抽象方法,还是实现类里面的重写方法,都是连接点。
解释:具备添加通知能力的方法位置,就是连接点,也就是所有类的所有方法。
(2).AOP切点(Pointcut)
AOP将可能被抽取共性功能的方法称为切入点。切入点是连接点的子集。
解释:成功添加了通知的方法位置,就是切点。
(3).AOP目标对象(Target)
就是挖掉功能的方法对应的类生的对象,这种对象是无法直接完成最终工作的。
解释:被代理对象,就是目标对象。
(4).AOP织入(Weaving)
就是将挖掉的功能回填的动态过程
解释:将通知添加到切点的过程ing,就是织入
(5).AOP切面:切点+通知
(6).SpringAOP+AspectJ实现步骤
1.坐标
2.配置
5、切点表达式配置语法
execution(修饰符 返回值 包名称.类名称.方法名称(参数列表))
eg:execution(public void com.apesource.service.ServiceImp.findAll())
(1).修饰符可以省略代表任意
execution(返回值 包名称.类名称.方法名称(参数列表))
(2).返回值可以使用“*”代表任意
execution(* 包名称.类名称.方法名称(参数列表))
(3).包名可以使用“*”代表任意名称
execution(* *.*.*.类名称.方法名称(参数列表))
eg:execution(void *.*.*.ServiceImp.findAll())
(4).包名可以使用“..”代表任意个数
execution(* *...类名称.方法名称(参数列表))
eg:execution(void *..ServiceImp.findAll())
(5).类名与方法名可以使用“*”代表任意
execution(* *...*.*(参数列表))
(6).参数列表可以使用".."代表任意个数任意类型
execution(* *...*.*(..))
如果有参数
int======>int
String===>java.lang.String
public interface IAccountService {//新增public void insert(int i);//修改public void update();//删除public int delete();
}
//注解 @Service
public class AccountServiceImp implements IAccountService {public void insert(int i) {System.out.println("业务层的新增方法:"+i);}public void update() {System.out.println("业务层的修改方法");// int a=10/0;}public int delete() {System.out.println("业务层的删除方法");return 0;}
}
// @Component
// @Aspect
public class Logger {// @Pointcut("execution(* com.apesource.service.*.*(..))")// public void dian(){// }//@Before("dian()")public void beforeLogger(){System.out.println("前置==日志类logger中调用printLogger方法进行日志记录");}//@AfterReturning("dian()")public void returnLogger(){System.out.println("返回==日志类logger中调用printLogger方法进行日志记录");}//@AfterThrowingpublic void throwLogger(){System.out.println("异常==日志类logger中调用printLogger方法进行日志记录");}//@After("dian()")public void afterLogger(){System.out.println("后置==日志类logger中调用printLogger方法进行日志记录");}//around替换上面的//@Around("dian()")// public Object aroundLogger(ProceedingJoinPoint pjp){// Object obje=null;// try {// System.out.println("环绕通知==前置");// Object[] args = pjp.getArgs();// obje=pjp.proceed(args);// System.out.println("环绕通知==返回");// } catch (Throwable e) {// System.out.println("环绕通知==异常");// throw new RuntimeException(e);// } finally {// System.out.println("环绕通知==后置");// }// return obje;// }
<!--xml-->
<!--注入业务层-->
<bean id="accountServiceImp" class="com.apesource.service.AccountServiceImp"></bean>
<!--注入日志记录层(通知)-->
<bean id="logger" class="com.apesource.util.Logger"></bean><!--配置AOP-->
<aop:config><!--配置切面 --><aop:aspect id="aopAspect" ref="logger"><!--切点--><aop:pointcut id="dian" expression="execution(public * com.apesource.service.*.*(..))"/><!--通知--><aop:before method="beforeLogger" pointcut-ref="dian"></aop:before><aop:after-returning method="returnLogger" pointcut-ref="dian"></aop:after-returning><aop:after-throwing method="throwLogger" pointcut-ref="dian"></aop:after-throwing><aop:after method="afterLogger" pointcut-ref="dian"></aop:after>// <aop:around method="aroundLogger" pointcut-ref="dian"></aop:around></aop:aspect>
</aop:config><!--注解-->// <context:component-scan base-package="com.apesource"></context:component-scan>
<!-- 注解驱动-->
<!-- @EnableAspectJAutoProxy-->// <aop:aspectj-autoproxy/>
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class Test01 {@Autowiredpublic IAccountService service;@Testpublic void show1(){service.update();}
八、循环依赖
注入双向对象引用属性演示
含义:多个实体之间相互依赖并形成闭环的情况就叫做"循环依赖",也叫做"循环引用。
解决方案:
Spring提供了三级缓存存储 完整Bean实例 和 半成品Bean实例 ,用于解决循环引用问题
在DefaultListableBeanFactory的上四级父类DefaultSingletonBeanRegistry中提供如下三个Map
public class DefaultSingletonBeanRegistry ... { //1、最终存储单例Bean成品的容器,即实例化和初始化都完成的Bean,称之为"一级缓存" Map<String, Object> singletonObjects = new ConcurrentHashMap(256); //2、早期Bean单例池,缓存半成品对象,且当前对象已经被其他对象引用了,称之为"二级缓存" Map<String, Object> earlySingletonObjects = new ConcurrentHashMap(16); //3、单例Bean的工厂池,缓存半成品对象,对象未被引用,使用时在通过工厂创建Bean,称之为"三 级缓存" Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
}
注:将对象保存至三级缓存的时候,会包装成ObjectFactory对象录入,
未来通过此接口对应的get方法再次提取对象.
UserService和UserDao循环依赖的过程结合上述三级缓存描述一下
UserService 实例化对象,但尚未初始化,将UserService存储到三级缓存;
UserService 属性注入,需要UserDao,从缓存中获取,没有UserDao;
UserDao实例化对象,但尚未初始化,将UserDao存储到到三级缓存;
UserDao属性注入,需要UserService,从三级缓存获取UserService,UserService从三级缓存移 入二级缓存;
UserDao执行其他生命周期过程,最终成为一个完成Bean,存储到一级缓存,删除二三级缓存;
UserService 注入UserDao;
UserService执行其他生命周期过程,最终成为一个完成Bean,存储到一级缓存,删除二三级缓
存。
九、常用的Aware接口
Aware接口是一种框架辅助属性注入的一种思想,其他框架中也可以看到类似的接口。框架具备高度封装性,我们接 触到的一般都是业务代码,一个底层功能API不能轻易的获取到,但是这不意味着永远用不到这些对象,如果用到了 ,就可以使用框架提供的类似Aware的接口,让框架给我们注入该对象 。
总结:处理器的作用,为Bean生命周期各个阶段提供扩展。