Spring5
Spring5课程介绍
- IOC容器;
2. AOP面向切面编程;
3. 声明事务;
4. 注解的方式启动对我们后期学习SpringBoot有非常大帮助;
5. 整合SpringMVC 和Mybatis;
6. Spring5新特性;
JDK最低版本要求1.8Spring概念
Spring是一个JavaEE开源的轻量级别的框架,可以解决我们企业开发中遇到的难题,
能够让编码变的更加简单,核心组件IOC容器和Aop面向切面编程。
1. IOC 控制反转:把整个对象创建的过程,统一交给我们SpringIOC容器来实现管理,底层使用反射+工厂模式实现。
2. Aop面向切面编程:对我们功能(方法)前后实现增强,比如打印日志、事务原理、权限管理,底层是基于动态代理模式实现的。
减少到我们的代码的冗余性问题。
Spring优势
- 方法的解耦,简化开发;
2. Aop技术的支持;
3. 提供声明事务支持
4. Junit单元测试
5. 方便整合其他框架(Mybatis、SpringMVC、SpringBoot、SpringCloud、Redis等)
6. 降低我们的JavaEEapi开发使用的难度(Spring对很多复杂的api接口实现了封装)Spring与SpringBoot关系
SpringBoot直接采用注解化的方式启动,底层会依赖于Spring/SpringMVC注解方式启动。
总结:SpringBoot底层基于Spring/SpringMVC注解化方式实现包装。
比如:
1.@RestController
2.@ComponentScan(“com.mayikt.aop”)
3. @Configuration
4. @Component
5. @Scheduled
6. @Value
7. @BeanSpringIOC底层容器原理
Spring框架快速入门
https://spring.io/ spring的官网
Spring官方下载依赖jar包地址:
https://repo.spring.io/webapp/#/artifacts/browse/tree/General/libs-release-local/org/springframework/spring
本次课以idea 构建maven项目方式讲解;
javadoc Api文档的介绍
Sources jar的源代码 .java
直接命名为.jar包的格式 就是class文件。七大核心模块
Test
对应spring-test.jar. Spring提供的测试工具, 可以整合JUnit测试, 简化测试环节.
Core Container
Spring的核心组件, 包含了Spring框架最基本的支撑.
Beans, 对应spring-beans.jar. Spring进行对象管理时依赖的jar包.
Core, 对应spring-core.jar, Spring核心jar包.
Context, 对应spring-context.jar, Spring容器上下文对象.
SpEL, 对应spring-expression.jar, Spring表达式语言.
AOP
面向切面编程, 对应spring-aop.jar.
Data Access
Spring对数据访问层的封装
JDBC, 对应spring-jdbc.jar. Spring对jdbc的封装, 当需要使用spring连接数据库时使用. spring-jdbc.jar需要依赖spring-tx.jar.
Transactions, 对应spring-tx.jar. 事务管理
ORM, 对应spring-orm.jar. spring整合第三方orm框架需要使用的jar包, 例如Hibernate框架.
Web
Spring对javax下的接口或类做的扩展功能.
spring-web.jar, 对Servlet, filter, Listener等做的增强.
spring-webmvc.jar, 实际上就是SpringMVC框架. 需要依赖spring环境和spring-web.jar.
Spring Core
核心容器提供Spring框架的基本功能。Spring以bean的方式组织和管理Java应用中的各个组件及其关系。Spring使用BeanFactory来产生和管理Bean,它是工厂模式的实现。BeanFactory使用控制反转(IoC)模式将应用的配置和依赖性规范与实际的应用程序代码分开。
Maven依赖:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
Spring-Beans
这个jar 文件是所有应用都要用到的,它包含访问配置文件、创建和管理bean 以及进行Inversion ofControl / Dependency Injection(IoC/DI)操作相关的所有类。如果应用只需基本的IoC/DI 支持,引入spring-core.jar 及spring-beans.jar 文件就可以了。
外部依赖spring-core,(CGLIB)。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
Spring Context
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
Spring上下文是一个配置文件,向Spring框架提供上下文信息。Spring上下文包括企业服务,如JNDI、EJB、电子邮件、国际化、校验和调度功能。
Spring-Expression
模块提供了一个强大的表达式语言,用于在运行时查询和处理对象图。该语言支持设置和获取属性值;属性赋值,方法调用,访问数组的内容,收集和索引器,逻辑和算术运算,命名变量,并从Spring的IOC容器的名字对象检索,它也支持列表选择和投影以及常见的列表聚合。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
Spring AOP
通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring框架中。所以,可以很容易地使 Spring框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖 EJB 组件,就可以将声明性事务管理集成到应用程序中。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
JDBC和DAO模块(Spring DAO)
JDBC、DAO的抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理,和不同数据库供应商所抛出的错误信息。异常层次结构简化了错误处理,并且极大的降低了需要编写的代码数量,比如打开和关闭链接。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
spring-transaction
以前是在这里org.springframework.transaction
为JDBC、Hibernate、JDO、JPA、Beans等提供的一致的声明式和编程式事务管理支持。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
Spring ORM
Spring框架插入了若干个ORM框架,从而提供了ORM对象的关系工具,其中包括了Hibernate、JDO和 IBatis SQL Map等,所有这些都遵从Spring的通用事物和DAO异常层次结构。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
Spring Web MVC
MVC框架是一个全功能的构建Web应用程序的MVC实现。通过策略接口,MVC框架变成为高度可配置的。MVC容纳了大量视图技术,其中包括JSP、POI等,模型来有JavaBean来构成,存放于m当中,而视图是一个街口,负责实现模型,控制器表示逻辑代码,由c的事情。Spring框架的功能可以用在任何J2EE服务器当中,大多数功能也适用于不受管理的环境。Spring的核心要点就是支持不绑定到特定J2EE服务的可重用业务和数据的访问的对象,毫无疑问这样的对象可以在不同的J2EE环境,独立应用程序和测试环境之间重用。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
项目构建
Maven依赖
<dependencies>
<!--
这个jar 文件包含Spring 框架基本的核心工具类。Spring 其它组件要都要使用到这个包里的类,是其它组件的基本核心,当然你也可以在自己的应用系统中使用这些工具类。
外部依赖Commons Logging, (Log4J)。
-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
<!--
这个jar 文件是所有应用都要用到的,它包含访问配置文件、创建和管理bean 以及进行Inversion ofControl / Dependency Injection(IoC/DI)操作相关的所有类。如果应用只需基本的IoC/DI 支持,引入spring-core.jar 及spring-beans.jar 文件就可以了。
外部依赖spring-core,(CGLIB)。
-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
<!--
这个jar 文件为Spring 核心提供了大量扩展。可以找到使用Spring ApplicationContext特性时所需的全部类,JDNI 所需的全部类,instrumentation组件以及校验Validation 方面的相关类。
外部依赖spring-beans, (spring-aop)。
-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
</dependencies>
创建spring.xml文件
| <?xml version=”1.0” encoding=”UTF-8”_?><beans xmlns=”http://www.springframework.org/schema/beans“ xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance"** xsi:schemaLocation=”http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"**>
_<!--_ 配置SpringBean对象_ -->_ _<**bean id="userEntity" class="com.mayikt.entity.UserEntity"**></**bean**>
</beans>
|
| —- |
获取Bean对象
// new UserEntity() // 1.读取xml配置文件 _ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext(“spring.xml”); // 2.根据bean的id获取bean对象 _UserEntity userEntity = classPathXmlApplicationContext.getBean(“userEntity”, UserEntity.class); System.**_out**.println(userEntity); userEntity.addUser(); |
---|
SpringIOC
IOC容器底层实现原理;
1.IOC容器中非常核心的接口 BeanFactory
BeanFactory
Bean对象 Factory工厂
2.IOC容器基本的概念:控制反转
把对象的创建过程与使用统一都交给我们的Spring来进行原理。
不需要开发者自己去new对象
3. IOC容器底层实现技术:反射技术、解析xml、工厂模式
4. IOC作用 降低我们代码的耦合度。
创建对象的方式有那些:
1. 单独new方式—-耦合度太高了
每次单独new对象,没有实现统一管理对象,如果后期userDao的名称信息发生变化的情况下,需要改变的引用地方比较多,耦合度太高。
2. 工厂模式—-降低我们耦合度
概念:统一的管理和维护我们每个对象创建与使用的过程。
不需要自己new对象。
3. 反射的方式
降低代码的-耦合度
Com.mayikt.dao—-数据库访问层;
Com.mayikt.service—-业务逻辑层;
业务逻辑层调用到数据库访问层
反射创建对象
SpringIOC容器底层实现原理:
反射+工厂模式+解析xml技术实现
1.使用解析xml技术 解析spring.xml配置文件;
2.获取
3.使用到反射技术初始化对象
4.需要使用工厂模式封装初始化对象
IOC核心的接口
- IOC的核心思想底层基于反射+工厂模式实现
2. Spring提供IOC容器实现两种方式:
2.1 BeanFactory IOC容器基本的实现,是spring内部自己使用的接口,不提供给开发者使用。
加载配置文件过程的时候,不会创建对象,当我们在获取对象的时候才会获取创建对象。
2.2 ApplicationContext BeanFactory 接口的子接口,提供更多的强大功能,适合于开发者使用。
当我们在加载配置文件的过程中,就会将配置文件中的对象创建。
在做服务器端开发的时候,使用ApplicationContext 比较多,因为所有bean初始化操作在项目启动完成之前都已经初始化了。
ApplicationContext主要实现类
ClassPathXmlApplicationContext:对应类路径下的XML格式的配置文件
FileSystemXmlApplicationContext:对应文件系统中的XML格式的配置文件
ConfigurableApplicationContext 是ApplicationContext的子接口,包含一些扩展方法
refresh()和close()让ApplicationContext具有启动、关闭和刷新上下文的能力。所以要关闭ApplicationContext需要new此接口的对象调用close()方法
WebApplicationContext 专门为WEB应用而准备的,它允许从相对于WEB根目录的路径中完成初始化工作
SpringBean的注入方式
创建对象和set方法注入属性
什么是Bean管理
使用spring创建对象
使用spring注入属性
2. Bean的管理有两种方式
1. 基于XML方式配置
基于XML方式创建对象
<bean id=”userEntity” class=”com.mayikt.entity.UserEntity”></bean>
在spring的配置文件中,会配置一个bean标签,注入bean的信息 创建bean对象
Id:获取bean对象 唯一bean对象的名称; bean的名称不允许重复
Class属性: 类的完整路径地址(类名称+包名称)
默认底层使用反射技术执行无参数构造函数基于xml方式注入属性
DI 依赖注入: 对象的属性注入值; (spring实现)
- 第一种实现方式:基于对象属性set方法实现
<bean id=”bookEntity” class=”com.mayikt.entity.BookEntity”> <property name=”bookName” value=”蚂蚁课堂面试宝典”></property> <property name=”bookPrice” value=”108.00”></property> </bean> 在Bean标签下 在定义一个属性<property>标签 Name:类中的属性名称 Value:需要注入属性值 |
---|
有参构造函数注入属性
实例类
| public class OrderEntity {
private String orderId;
private String orderName;
**public **OrderEntity(String orderId, String orderName) {<br /> **this**.**orderId **= orderId;<br /> **this**.**orderName **= orderName;<br /> }
@Override<br /> **public **String toString() {<br /> **return "OrderEntity{" **+<br /> **"orderId='" **+ **orderId **+ **'\\'' **+<br /> **", orderName='" **+ **orderName **+ **'\\'' **+<br /> **'}'**;<br /> }<br />}<br /> |
| —- |
Xml配置文件
<bean id=”orderEntity” class=”com.mayikt.entity.OrderEntity”> <!— <constructor-arg index=”1” value=”蚂蚁课堂第八期订单”></constructor-arg> </bean> |
---|
<constructor-arg name 指定参数列表名称
<constructor-arg index 指定参数列表索引
p名称空间注入
- Xml头部引入P标签:
<?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:p=”http://www.springframework.org/schema/p"** xsi:schemaLocation=”http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"**> |
---|
- 使用p标签注入属性:
<bean id=”bookEntity” class=”com.mayikt.entity.BookEntity” p:bookName=”mayikt” p:bookPrice=”66”> </bean> |
---|
使用p标签为属性注入值:调用set方法注入值
注入空值和特殊符号
注入空值属性
<bean id=”bookEntity2” class=”com.mayikt.entity.BookEntity”> <property name=”bookName” value=”mayikt”> </property> <property name=”bookPrice” > <null></null> </property> |
---|
注入特殊符号
转移注入方式
<< 转移为:<<
>>转移为:>>
<bean id=”bookEntity3” class=”com.mayikt.entity.BookEntity”> _<property name=”bookName” value=”<<武汉>>”></property> <property name=”bookPrice”> <null></null> </property> </bean> |
---|
Cdata注入方式
<![CDATA[<<>>]]>
<bean id=”bookEntity4” class=”com.mayikt.entity.BookEntity”> _<property name=”bookName”> <value><![CDATA[<<武汉>>]]></value> </property> <property name=”bookPrice”> <null></null> </property> </bean> |
---|
注入属性外部bean
Com.mayikt.controller—-控制层
Com.mayikt.service——业务逻辑层
MemberService ##new MemberDao().
Com.mayikt.dao——数据库访问层
MemberDao——
Com.mayikt.service
调用:memberService
Com.mayikt.dao
MemberDaoImpl
|
public interface MemberDao {
void addMember();
}
public class MemberDaoImpl implements MemberDao {
public void addMember() {
System.out.println(“dao member”);
}
}
import com.mayikt.dao.MemberDao;
import com.mayikt.dao.MemberDaoImpl;
public class MemberService {
private MemberDao memberDao;
public MemberDao getMemberDao() {<br /> return memberDao;<br /> }
public void setMemberDao(MemberDao memberDao) {<br /> this.memberDao = memberDao;<br /> }
public void addMember() {<br /> System._out_.println("<<<Service Service>>");<br /> _// 原始的方式_// MemberDao memberDao = new MemberDaoImpl();_// memberDao.addMember();_ _memberDao.addMember();<br /> }<br />}<br /><br />_<?_xml version="1.0" encoding="UTF-8"_?><beans xmlns="http://www.springframework.org/schema/beans"<br /> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"<br /> xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
_<!--_ 注入useService_ -->_ _<bean id="memberService" class="com.mayikt.service.MemberService"><br /> _<!-- 注入userDao_ name 属性值: 类中属性的名称;_ ref 创建MemberDaoImpl类的 bean的id_ -->_ _<property name="memberDao" ref="memberDao"></property><br /> </bean><br /> <bean id="memberDao" class="com.mayikt.dao.MemberDaoImpl"></bean><br /></beans><br /><br /> |
| —- |
注入内部bean
- 数据库表一对多或者一对一的关系
2. 部门—n多个员工 一对多
3. 站在员工角度考虑员工属于那个部门
4. 站在部门的角度考虑部门下n多个员工
- 在数据库中表中有一对一一对多的关系;
2. 一对多关系;部门与员工 一个部门会有多个员工 一个员工属于一个部门;
3. 实体类之间表示一对多的关系;
实体类员工对象
| public class EmpEntity {
private String name;<br /> private Integer age;<br /> _/**_ * 员工属于那个部门_ */_ _private DeptEntity deptEntity;<br /> public void setName(String name) {<br /> this.name = name;<br /> }
public String getName() {<br /> return name;<br /> }
public Integer getAge() {<br /> return age;<br /> }
public void setAge(Integer age) {<br /> this.age = age;<br /> }
public void setDeptEntity(DeptEntity deptEntity) {<br /> this.deptEntity = deptEntity;<br /> }
@Override<br /> public String toString() {<br /> return "EmpEntity{" +<br /> "name='" + name + '\\'' +<br /> ", age=" + age +<br /> ", deptEntity=" + deptEntity +<br /> '}';<br /> }<br />}<br /> |
| —- |
部门对象
| public class DeptEntity {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override<br /> public String toString() {<br /> return "DeptEntity{" +<br /> "name='" + name + '\\'' +<br /> '}';<br /> }<br />}<br /> |
| —- |
Xml相关配置
|
_
|
| —- |
注入级联赋值
写法1
写法2
注意:需要在员工实体类新增:deptEntity get方法。
注入集合类型属性
- 注入数组类型
2. 注入list集合类型
3. 注入Map集合类型属性
4. 注入set集合属性
实体类
|
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class StuEntity {
//1.数组属性 private String[] arrays;
//2.list集合属性 _private List
public void setArrays(String[] arrays) {<br /> this.arrays = arrays;<br /> }
public void setList(List<String> list) {<br /> this.list = list;<br /> }
public void setMap(Map<String, String> map) {<br /> this.map = map;<br /> }
public void setSet(Set<String> set) {<br /> this.set = set;<br /> }
@Override<br /> public String toString() {<br /> return "StuEntity{" +<br /> "arrays=" + Arrays._toString_(arrays) +<br /> ", list=" + list +<br /> ", map=" + map +<br /> ", set=" + set +<br /> '}';<br /> }<br />}<br /> |
| —- |
配置文件
集合类型为对象
| private List
public void setCourses(List
this.courses = courses;
}
public class CourseEntity {
private String name;
public void setName(String name) {<br /> this.name = name;<br /> }
@Override<br /> public String toString() {<br /> return "CourseEntity{" +<br /> "name='" + name + '\\'' +<br /> '}';<br /> }<br />}<br /> |
| —- |
| <?_xml version=”1.0” encoding=”UTF-8”?>
xsi:schemaLocation=”http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="stuEntity" class="com.mayikt.entity.StuEntity"><br /> _<!--对我们的list属性赋值-->_ _<property name="list"><br /> <list><br /> <value>list01</value><br /> <value>list02</value><br /> </list><br /> </property><br /> _<!--对我们的arrays属性赋值-->_ _<property name="arrays"><br /> <array><br /> <value>mayikt01</value><br /> <value>mayikt02</value><br /> </array><br /> </property><br /> _<!--对我们的map属性赋值-->_ _<property name="map"><br /> <map><br /> <entry key="mayikt" value="余胜军"></entry><br /> <entry key="xiaowei" value="小薇"></entry><br /> </map><br /> </property><br /> _<!--对我们的set属性赋值-->_ _<property name="set"><br /> <set><br /> <value>list01</value><br /> <value>list02</value><br /> </set><br /> </property><br /> <property name="courses" ><br /> <list><br /> <ref bean="courseEntity1"></ref><br /> <br /> |
| —- |
集合注入部分提取公共
- 需要先引入一个util名称空间
<?_xml version=”1.0” encoding=”UTF-8”?> xmlns:util=”http://www.springframework.org/schema/util“ xsi:schemaLocation=”http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> |
---|
- 使用util标签 注入
| <?_xml version=”1.0” encoding=”UTF-8”?>
xmlns:util=”http://www.springframework.org/schema/util“
xsi:schemaLocation=”http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
_<!-- 提取公共部分-->_ _<util:list id="list"><br /> <value>mayikt01</value><br /> <value>mayikt02</value><br /> </util:list><br /> <bean id="stuEntity" class="com.mayikt.entity.StuEntity"><br /> <property name="list" ref="list"></property><br /> </bean><br /></beans> |
| —- |
IOC操作Bean的管理
- Spring中两种类型bean,一种是为普通的bean,另外一种是工厂bean
FactoryBean
2. 普通Bean:在配置文件中定义什么类型与返回的类型需一致;
3. 工厂Bean:在配置文件中定义Bean类型与返回类型可以不一致;
创建一个类,这个类是为工厂Bean,实现FactoryBean接口
| import com.mayikt.entity.UserEntity;
import org.springframework.beans.factory.FactoryBean;
public class MayiktBean implements FactoryBean
/** 定义返回bean_ * @return @throws Exception_ /_ _public UserEntity getObject() throws Exception {
return new UserEntity();
}
public Class<?> getObjectType() {<br /> return null;<br /> }<br />}<br /> |
| —- |
public static void main(String[] args) { ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext(“spring08.xml”); UserEntity mayiktBean = (UserEntity) app.getBean(“mayiktBean”); System._out.println(mayiktBean); } |
---|
Spring的工厂Bean
SpringBean的作用域
什么是作用域?
设定bean作用域是为单例还是多例
作用域单例与多例有什么区别呢?
1. 单例的作用域:每次在调用getbean方法获取对象都是为同一个对象;
2. 多例的作用域:每次在调用getbean方法获取对象都是一个
新的对象。
注意:在spring默认的情况下,bean的作用域就是为单例 节约服务器内存。
单例:
在同一个jvm中,该bean对象只会创建一次。
多例:
在同一个jvm中,该bean对象可以被创建多次。
设定对象单例还是多例
在spring的默认的情况下,springbean的作用域为单例。
1.单例就是每次获取bean都是同一个对象;
2.多例就是每次获取bean都是新的一个对象;
单例:在同一个jvm中该bean只能存在一个实例;
多例子:在同一个jvm中该bean存在多个实例;
证明:如果是为单例,则两个对象地址都是一样的,
多例子对象则两个对象地址不一样。
单例配置:
默认就是为单例子;
多例配置:
SpringBean的生命周期
简单分为:实例化→属性赋值→初始化→销毁
生命周期概念:
1. 对象的创建与销毁的过程,类似之前学习servlet生命的周期过程。
生命周期的原理:
1. 通过构造函数创建bean对象(默认执行无参构造函数 底层基于反射实现)
2. 为bean的属性设置 (使用反射调用set方法)
3. 调用bean的初始化的方法(需要单独在类中配置初始化的方法)
4. 正常使用bean对象
5. Spring容器关闭,调用该类的销毁回调的方法(需要单独在类中配置销毁的方法)
| public class MemberEntity {
private String name;
public MemberEntity(){
System.out.println(“[第一步]-无参构造函数被执行—-反射机制调用”);
}
public void setName(String name) {<br /> System._out_.println("[第二步]-set方法初始化属性---反射机制调用");<br /> this.name = name;<br /> }
_/**_ * 回调调用init初始化方法_ */_ _public void initMethod(){<br /> System._out_.println("[第三步]-回调调用init初始化方法");<br /> }
_/**_ * destroyMethod_ */_ _public void destroyMethod(){<br /> System._out_.println("[第五步]-回调调用destroyMethod方法");<br /> }<br />}<br /> |
| —- |
| import com.mayikt.entity.MemberEntity;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test07 {
public static void main(String[] args) {
ClassPathXmlApplicationContext app =
new ClassPathXmlApplicationContext(“spring07.xml”);
MemberEntity memberEntity= app.getBean(“memberEntity”,MemberEntity.class);
System._out.println(“[第四步]-获取使用到的memberEntity”);
System.out.println(memberEntity);
// 手动让bean容器销毁 _app.close();
}
} |
| —- |
Bean的后置处理器 作用提供更多的扩展功能 BeanPostProcessor
相关演示代码
|
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class MayiktBeanPost implements BeanPostProcessor {
/** 调用初始化方法之前执行_ @param bean * @param beanName @return_ @throws BeansException */ public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System._out.println(“在bean 初始化方法之前执行”);
return bean;
}
_/**_ * 调用初始化方法之后执行_ * @param bean_ * @param beanName_ * @return_ * @throws BeansException_ */_ _public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {<br /> System._out_.println("在bean 初始化方法之后执行");<br /> return bean;<br /> }<br />}<br /> |
| —- |
1.通过构造函数创建bean对象(默认执行无参构造函数 底层基于反射实现)
2.为bean的属性设置 (使用反射调用set方法)
3.将bean传递给后置处理器 调用初始化方法之前执行
4.调用bean的初始化的方法(需要单独在类中配置初始化的方法)
5.将bean传递给后置处理器 调用初始化方法之后执行
6.正常使用bean对象
7.Spring容器关闭,调用该类的销毁回调的方法(需要单独在类中配置销毁的方法)
后置处理器底层原理
配置多个BeanPostProcessor
|
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.Ordered;
public class MayiktBeanPost implements BeanPostProcessor, Ordered {
/** 调用初始化方法之前执行_ @param bean * @param beanName @return_ @throws BeansException */ public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System._out.println(“调用该bean的 init方法之前”);
return bean;
}
_/**_ * 调用初始化方法之后执行_ * @param bean_ * @param beanName_ * @return_ * @throws BeansException_ */_ _public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {<br /> System._out_.println("调用该bean的 init方法之后");<br /> return bean;<br /> }
public int getOrder() {<br /> return 1;<br /> }<br />}<br /> |
| —- |
| import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.Ordered;
public class MayiktBeanPost02 implements BeanPostProcessor, Ordered {
/** 调用初始化方法之前执行_ @param bean * @param beanName @return_ @throws BeansException */ public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System._out.println(“[MayiktBeanPost02:]调用该bean的 init方法之前”);
return bean;
}
_/**_ * 调用初始化方法之后执行_ * @param bean_ * @param beanName_ * @return_ * @throws BeansException_ */_ _public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {<br /> System._out_.println("[MayiktBeanPost02:]调用该bean的 init方法之后");<br /> return bean;<br /> }
public int getOrder() {<br /> return 0;<br /> }<br />}<br /> |
| —- |
_ |
---|
实现Ordered接口 getOrder 值越小越优先加载
SpringBean的自动装配
什么是自动装配呢
根据装配的规则(属性的名称或者属性的类型)
Spring根据装配的规则自动为属性注入值。
- 什么是自动装配
A. 根据指定装配规则(属性名称或者属性的类型),spring自动
将匹配属性的值注入。
| <?_xml version=”1.0” encoding=”UTF-8”?>
xmlns:util=”http://www.springframework.org/schema/util“
xsi:schemaLocation=”http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
_<!-- spring ioc <bean id="empEntity" class="com.mayikt.entity.EmpEntity">_ <property name="deptEntity" ref="deptEntity"></property>_ </bean> -->__ <!-- bean 标签中有一个属性autowire_ 1.根据属性的名称注入 bean的id名称与属性的名称一致_ 2.根据属性的类型注入 bean的类型与属性类型一致_ -->_ _<bean id="empEntity" class="com.mayikt.entity.EmpEntity" autowire="byType">
</bean><br /> <bean id="deptEntity" class="com.mayikt.entity.DeptEntity"><br /> <property name="name" value="教育部门"></property><br /> </bean><br /> <br /></beans><br /> |
| —- |
SpringBean的外部属性文件
SpringBean的注解形式
Spring的注解启动方式
Bean的管理操作方式
1. 基于XML方式实现
2. 基于注解方式实现
什么是注解:注解是JDK5中推出的新特性,代码的特殊标记,
格式注解名称“属性名称=属性值,属性名称=属性值”。
我们在后期学习springboot开发基本上都是使用注解,很少在使用
Xml配置的方式。
注解可以使用在类、方法、属性、上面。
使用注解的目的,简化xml的配置方式。
Spring提供的常用注解
1. @Component 将对象注入Spring容器中
2. @Service 注入业务逻辑对象
3. @Controller 控制器类
4. @Repository 注入dao对象
5. 以上该四个注解底层都是基于@Component注解封装的,只是区分用于
在不同的场景下。
注解的使用方式
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(); app.register(BeanConfig.class); app.refresh(); MemberEntity memberEntity = (MemberEntity) app.getBean(“memberEntity”); System.out.println(memberEntity); |
---|
SpringBean的AOP
AOP基本的概念
AOP(Aspect Oriented Programming)是一种面向切面的编程思想。面向切面编程是将程序抽象成各个切面,即解剖对象的内部,将那些影响了多个类的公共行为抽取到一个可重用模块里,减少系统的重复代码,降低模块间的耦合度,增强代码的可操作性和可维护性。
AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理、增强处理。
简单理解:
Aop面向切面编程,在方法之前和之后实现处理 应用场景在于:日志打印、事务实现、安全、权限控制、自定义注解等。
因为AOP可以解决我们程序上的代码冗余问题
AOP 底层基于 代理设计模式封装
代理设计模式 静态代理与动态代理
动态代理 jdk动态代理与 cglib动态代理
通俗易懂 aop 在我们的目标方法之前和之后 处理的操作
开启事务
目标方法
提交或者回滚事务
提交或者回滚事务
aop 日志打印 事务原理 自定义实现
代理模式实现的原理
代理模式主要包含三个角色,即抽象主题角色(Subject)、委托类角色(被代理角色,Proxied)以及代理类角色(Proxy),如上图所示:
抽象主题角色:可以是接口,也可以是抽象类;
委托类角色:真实主题角色,业务逻辑的具体执行者;
代理类角色:内部含有对真实对象RealSubject的引用,负责对真实主题角色的调用,并在真实主题角色处理前后做预处理和后处理。
代理模式创建方式
相关测试代码:
package com.mayikt.service;
/**
* @author 余胜军
* @ClassName OrderService
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
public interface OrderService {
/**
* 添加订单数据
*/
String addOrder(String orderName);
}
package com.mayikt.service.impl;
import com.mayikt.service.OrderService;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class OrderServiceImpl implements OrderService {
@Override
public String addOrder(String orderName) {
log.info("<orderName:{}>", orderName);
return "ok";
}
}
静态代理
基于接口实现方式
package com.mayikt.proxy1;
import com.mayikt.service.OrderService;
import lombok.extern.slf4j.Slf4j;
/**
* @author 余胜军
* @ClassName OrderServiceProxy
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
@Slf4j
public class OrderServiceProxy implements OrderService {
private OrderService orderService;
public OrderServiceProxy(OrderService orderService) {
this.orderService = orderService;
}
@Override
public String addOrder(String orderName) {
// 目标方法前后处理操作
log.info("<目标方法之前执行...>");
String result = orderService.addOrder(orderName);
log.info("<目标方法之后执行...>");
return result;
}
}
package com.mayikt.proxy1;
import com.mayikt.service.impl.OrderServiceImpl;
/**
* @author 余胜军
* @ClassName Test01
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
public class Test01 {
public static void main(String[] args) {
OrderServiceProxy orderServiceProxy = new OrderServiceProxy(new OrderServiceImpl());
String result = orderServiceProxy.addOrder("mayikt");
System.out.println(result);
}
}
基于继承实现方式
package com.mayikt.proxy2;
import com.mayikt.service.impl.OrderServiceImpl;
import lombok.extern.slf4j.Slf4j;
/**
* @author 余胜军
* @ClassName OrderServiceProxy
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
@Slf4j
public class OrderServiceProxy extends OrderServiceImpl {
@Override
public String addOrder(String orderName) {
// 目标方法前后处理操作
log.info("<目标方法之前执行...>");
String result = super.addOrder(orderName);
log.info("<目标方法之后执行...>");
return result;
}
}
package com.mayikt.proxy2;
/**
* @author 余胜军
* @ClassName Test01
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
public class Test01 {
public static void main(String[] args) {
OrderServiceProxy orderServiceProxy = new OrderServiceProxy();
String result = orderServiceProxy.addOrder("mayikt");
System.out.println(result);
}
}
动态代理
动态代理是在实现阶段不用关心代理类,而在运行阶段才指定哪一个对象。
动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成 。
JDK动态代理的一般步骤如下:
1.创建被代理的接口和类;
2.实现InvocationHandler接口,对目标接口中声明的所有方法进行统一处理;
3.调用Proxy的静态方法,创建代理类并生成相应的代理对象;
实现原理:利用拦截器机制必须实现InvocationHandler接口中的invoke方法实现对
我们的目标方法增强。
JDK API动态代理用法
package com.mayikt.proxy3;
import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @author 余胜军
* @ClassName JdkInvocationHandler
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
@Slf4j
public class JdkInvocationHandler implements InvocationHandler {
/**
* 目标对象
*/
private Object target;
public JdkInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log.info("<jdk动态代理目标方法之前>,args:{}", args);
Object result = method.invoke(target, args);
log.info("<jdk动态代理目标方法之后,args:{}", args);
return result;
}
public <T> T getProxy() {
return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
}
package com.mayikt.proxy3;
import com.mayikt.service.OrderService;
import com.mayikt.service.impl.OrderServiceImpl;
/**
* @author 余胜军
* @ClassName Test01
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
public class Test01 {
public static void main(String[] args) {
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
JdkInvocationHandler jdkInvocationHandler = new JdkInvocationHandler(new OrderServiceImpl());
OrderService orderService = jdkInvocationHandler.getProxy();
orderService.addOrder("mayikt");
}
}
动态代理与静态代理的区别
动态代理不需要写代理类对象,通过程序自动生成,而静态代理需要我们自己写代理类对象。
JDK动态代理原理分析
- 获取代理的生成的class文件
System.getProperties().put(“sun.misc.ProxyGenerator.saveGeneratedFiles”, “true”);
```java // // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) //
package com.sun.proxy;
import com.mayikt.service.OrderService; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy0 extends Proxy implements OrderService { private static Method m1; private static Method m3; private static Method m2; private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String addOrder(String var1) throws {
try {
return (String)super.h.invoke(this, m3, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m3 = Class.forName("com.mayikt.service.OrderService").getMethod("addOrder", Class.forName("java.lang.String"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
注意:继承了Proxy类,实现了代理的接口,由于java不能多继承,这里已经继承了Proxy类了,不能再继承其他的类,所以JDK的动态代理不支持对实现类的代理,只支持接口的代理。
```java
public static void main(String[] args) {
$Proxy0 $Proxy0 = new $Proxy0(new JdkInvocationHandler(new OrderServiceImpl()));
$Proxy0.addOrder("mayikt");
}
public <T> T getProxy() {
return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
this);
生成代理类时 会传递我们目标对象实现哪些接口
target.getClass().getInterfaces()
如果我们目标对象没有实现接口 jdk动态代理生成代理类 也没有实现接口
使用jdk动态代理时 注意 让目标对象实现接口, 生成代理类时 实现目标对象的接口
方便可以使用接口调用目标对象的方法
1.执行到我们 代理类中$Proxy0.addOrder()
2.执行到我们MayiktInvocationHandler.invoke
public final String addOrder(String var1) {
try {
return (String) super.h.invoke(this, m3, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
3.执行到我们MayiktInvocationHandler.invoke 在根据java反射机制 传递目标对象 调用目标方法
mybatis mapper接口分析
在mybatis mapper 是一个接口为何可以调用的呢?底层其实就是基于JDK动态代理实现。
相关代码:
package com.mayikt.mybatis.ext;
import org.springframework.stereotype.Indexed;
import java.lang.annotation.*;
/**
* @author 余胜军
* @ClassName MayiktInsert
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface MayiktInsert {
String value();
}
package com.mayikt.mybatis;
import com.mayikt.mybatis.ext.MayiktInsert;
import com.mayikt.utils.MayiktJdbcUtils;
import org.apache.commons.lang.StringUtils;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.PreparedStatement;
/**
* @author 余胜军
* @ClassName MybatisJdkInvocationHandler
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
public class MybatisJdkInvocationHandler implements InvocationHandler {
private Class mapperClass;
public MybatisJdkInvocationHandler(Class mapperClass) {
this.mapperClass = mapperClass;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 使用java反射技术获取该方法上的注解
MayiktInsert declaredAnnotation = method.getDeclaredAnnotation(MayiktInsert.class);
String insertSql = declaredAnnotation.value();
if (StringUtils.isEmpty(insertSql)) {
return null;
}
// 执行该sql语句
Connection connection = MayiktJdbcUtils.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement(insertSql);
int result = preparedStatement.executeUpdate();
return result;
}
public <T> T getProxy() {
return (T) Proxy.newProxyInstance(mapperClass.getClassLoader(), new Class[]{mapperClass}, this);
}
}
package com.mayikt.mybatis;
import com.mayikt.mybatis.ext.MayiktInsert;
/**
* @author 余胜军
* @ClassName UserMapper
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
public interface UserMapper {
@MayiktInsert("INSERT INTO `mayikt`.`mayikt_users` (`id`, `name`, `age`) VALUES (null, 'wangmazi', NULL);")
int addUser();
}
package com.mayikt.mybatis;
/**
* @author 余胜军
* @ClassName Test01
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
public class Test01 {
public static void main(String[] args) {
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
UserMapper userMapper = MapperProxy.getUserMapper(UserMapper.class);
int result = userMapper.addUser();
System.out.println(result);
}
}
package com.mayikt.mybatis;
/**
* @author 余胜军
* @ClassName MapperProxy
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
public class MapperProxy {
public static UserMapper getUserMapper(Class mapperClass) {
return new MybatisInvocationHandler(mapperClass).getProxy();
}
public static void main(String[] args) {
// 将jdk动态生成好的 class 存放本地
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
UserMapper userMapper = MapperProxy.getUserMapper(UserMapper.class);
int i = userMapper.addUser();
System.out.println(i);
}
}
什么是CGLIB 动态代理
Cglib 底层基于asm实现
Cglib 与jdk动态代理到底有哪些区别呢?
jdk动态代理底层基于反射方式调用目标方法 jdk7之前效率是非常低后期优化。
Cglib 底层是反射调用目标方法效率非常低 ,直接采用建立fastclass 索引的方式
调用目标方法。
jdk7之前Cglib动态代理效率是比我们jdk动态代理效率高非常多
jdk7开始jdk动态代理是我们Cglib动态代理效率高。
Cglib动态代理生成的代理类 直接 继承 被代理类(实现继承方式代理)
public class OrderServiceImplEnhancerByCGLIB1dd3a71c extends OrderServiceImpl implements Factory {
jdk动态代理生成代理类 实现 被代理实现的接口 (实现接口方式代理)
Cglib底层生成代理类是通过 asm 生成字节码 class
1.Cglib是一个强大的,高性能,高质量的代码生成类库。它可以在运行期扩展JAVA类与实现JAVA接口。其底层实现是通过ASM字节码处理框架来转换字节码并生成新的类。大部分功能实际上是ASM所提供的,Cglib只是封装了ASM,简化了ASM操作,实现了运行期生成新的class。
2.运行时动态的生成一个被代理类的子类(通过ASM字节码处理框架实现),子类重写了被代理类中所有非final的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势植入横切逻辑。
3.jdk7开始 jdk动态代理效率比cglib要高
spring底层采用 cglib代理类?还是jdk动态代理
判断 被代理类 实现接口 使用jdk动态代理
如果被代理类 没有实现接口则使用cglib代理类
cglib基本用法
<dependencies>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.12</version>
</dependency>
</dependencies>
实现MethodInterceptor接口的intercept方法后,所有生成的代理方法都调用这个方法。
intercept方法的具体参数有
obj 目标类的实例
1. method 目标方法实例(通过反射获取的目标方法实例)
2. args 目标方法的参数
3. proxy 代理类的实例
该方法的返回值就是目标方法的返回值。
package com.mayikt.service;
/**
* @author 余胜军
* @ClassName OrderService
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
public interface OrderService {
/**
* 添加订单数据
*/
String addOrder(String orderName);
}
package com.mayikt.service.impl;
import com.mayikt.service.OrderService;
import lombok.extern.slf4j.Slf4j;
/**
* @author 余胜军
* @ClassName OrderServiceImpl
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
@Slf4j
public class OrderServiceImpl implements OrderService {
// @Override
public String addOrder(String orderName) {
log.info("<orderName:{}>", orderName);
// addorder相关的事情
return "ok";
}
}
package com.mayikt.cglib;
import lombok.extern.slf4j.Slf4j;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* @author 余胜军
* @ClassName MayiktCglibMethodInterceptor
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
@Slf4j
public class MayiktCglibMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
log.info("<目标方法之前开始执行....>");
// Object result = method.invoke(obj, args);
Object result = proxy.invokeSuper(obj, args);
log.info("<目标方法之后开始执行....>");
return result;
}
}
package com.mayikt.cglib;
import com.mayikt.service.impl.OrderServiceImpl;
import net.sf.cglib.core.DebuggingClassWriter;
import net.sf.cglib.proxy.Enhancer;
public class Test01 {
public static void main(String[] args) {
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\code\\cglib");
MayiktCglibMethodInterceptor mayiktCglibMethodInterceptor = new MayiktCglibMethodInterceptor();
Enhancer enhancer = new Enhancer();
// 设置代理
enhancer.setSuperclass(OrderServiceImpl.class);
// 设置cglib 回调类
enhancer.setCallback(mayiktCglibMethodInterceptor);
// 创建cglib代理类
OrderServiceImpl orderServiceImpl = (OrderServiceImpl) enhancer.create();
String result = orderServiceImpl.addOrder("mayikt");
System.out.println(result);
}
}
AOP详解
Aop常用术语
1.连接点(Join point): 连接点表示应用执行过程中能够插入切面的一个点,这个点可以是方法的调用、异常的抛出。在 Spring AOP 中,连接点总是方法的调用。类中的哪些方法可以被增强,这些方法就被称作为连接点。
2.切点(PointCut): 可以插入增强处理的连接点,实际被增强的方法就称作为切入点
3.通知(Advice): AOP 框架中的增强处理,通知描述了切面何时执行以及如何执行增强处理, 实际增强的业务逻辑,该过程就可以称作为通知 前置、后置、环绕通知
4.切面(Aspect): 切面是通知和切点的结合。 把通知应用到的过程 就是为切面
5.引入(Introduction):允许我们向现有的类添加新的方法或者属性。
6.织入(Weaving): 将增强处理添加到目标对象中,并创建一个被增强的代理对象
1.连接点 该类中哪些方法需要被增强,这些方法就可以称作连接点
3.切点 实际被增强的方法
2.通知 在方法前后执行代码
前置通知 调用方法之前处理…
后置通知 调用完该方法之后处理
环绕通知 在我们被代理方法前后执行
异常通知
最终通知
4.切面 把通知应用到的过程 就是为切面
Aop环境准备
1.Spring框架一般都是基于AspectJ实现AOP操作
(1)什么是AspectJ
AspectJ是一个面向切面的框架,它扩展了Java语言。AspectJ定义了AOP语法,它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件,AspectJ不是Spring组成部分,独立AOP框架,一般把AspectJ和Spring框架一起使用,进行AOP操作.
2.基于AspectJ实现AOP
(1)基于xml配置文件实现
(2)基于注解方式(偏多的)
3.在项目工程目录引入AOP依赖
maven依赖
<!-- aspectj支持 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.9</version>
</dependency>
<dependency>
<groupId>org.apache.geronimo.bundles</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.8_2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
切入点表达式
具体那个类中的那个方法来实现增强
需要描述 该类中哪些方法是需要被增强——-切入点规则
execution( [权限修饰符] [返回类型] [类全路径] [方法名称] ([参数列表]));
[权限修饰符
1.public.String.com.mayikt.service.MayiktService.addUser(..) —拦截的是
MayiktService类中addUser方法名称 所有参数 返回值String
2. com.mayikt.service.MayiktService.(..)拦截我们的
MayiktService类中的所有方法
3. com.mayikt.service..*(..)拦截就是我们 com.mayikt.service.包下
的所有的类所有的方法。
(1)语法接口:
execution( [权限修饰符] [返回类型] [类全路径] [方法名称] ([参数列表]));
//举例1:对com.mayikt.service.MayiktService类里面的 add() 进行增强 execution(com.mayikt.service.MayiktService.add(..)); // 表示所有, .. 表示参数列表
//举例2:对com.mayikt.service.MayiktService类里面的 所有方法 进行增强 execution(com.mayikt.service.MayiktService.(..));
//举例3:对com.mayikt.service.MayiktService所有类里面的 所有方法 进行增强 execution(com.mayikt.service.MayiktService..*(..));
切入点表达式
测试代码
package com.mayikt.service;
import org.springframework.stereotype.Component;
/**
* @author 余胜军
* @ClassName MayiktService
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
@Component
public class MayiktService {
public String addMayikt() {
System.out.println("addMayikt...");
return "ok";
}
}
package com.mayikt.proxy;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/**
* @author 余胜军
* @ClassName UserProxy
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
@Component
@Aspect// aop 代理
public class UserProxy {
/**
* 前置通知
*/
@Before("execution(* com.mayikt.service.MayiktService.addMayikt(..));")
public void before() {
System.out.println("前置通知...");
}
/**
* 后置通知
*/
@After("execution(* com.mayikt.service.MayiktService.addMayikt(..));")
public void after() {
System.out.println("后通知...");
}
/**
* 环绕通知
*/
@Around(value = "execution(* com.mayikt.service.MayiktService.addMayikt(..));")
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕通知...");
System.out.println("目标方法之前开始执行...");
Object result = proceedingJoinPoint.proceed();
System.out.println("目标方法之后开始执行...");
return result;
}
//@AfterReturning表达后置通知/返回通知,表达方法返回结果之后执行
@AfterReturning(value = "execution(* com.mayikt.service.MayiktService.addMayikt(..));")
public void afterReturning() {
System.out.println("afterReturning");
}
//@AfterThrowing表达异常通知
@AfterThrowing(value = "execution(* com.mayikt.service.MayiktService.addMayikt(..));")
public void afterThrowing() {
System.out.println("afterThrowing");
}
}
开启springaop
<?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"
xmlns:aop="http://www.springframework.org/schema/aop"
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.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
">
<!--开启注解方式 -->
<context:component-scan base-package="com.mayikt"></context:component-scan>
<!--开启 aspectj 生成代理-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
ClassPathXmlApplicationContext app =
new ClassPathXmlApplicationContext("spring_07.xml");
MayiktService mayiktService = app.getBean("mayiktService", MayiktService.class);
mayiktService.addMayikt();
spring框架种使用 cglib?jdk动态代理?
spring aop 底层基于 代理封装?
如果我们 被代理类 没有实现接口的情况下 则使用 cglib动态代理
如果我们被代理类 有实现接口的情况下 则使用 jdk动态代理