spring框架

Spring5

Spring概念

Spring是一个JavaEE开源的轻量级别的框架,可以解决我们企业开发中遇到的难题,

能够让编码变的更加简单,核心组件IOC容器和Aop面向切面编程。

1. IOC 控制反转:把整个对象创建的过程,统一交给我们SpringIOC容器来实现管理,底层使用反射+工厂模式实现。

2. Aop面向切面编程:对我们功能(方法)前后实现增强,比如打印日志、事务原理、权限管理,底层是基于动态代理模式实现的。

减少到我们的代码的冗余性问题。

Spring优势

1. 方法的解耦,简化开发;

2. Aop技术的支持;

3. 提供声明事务支持

4. Junit单元测试

5. 方便整合其他框架(Mybatis、SpringMVC、SpringBoot、SpringCloud、Redis等)

6. 降低我们的JavaEEapi开发使用的难度(Spring对很多复杂的api接口实现了封装)

SpringSpringBoot关系

SpringBoot直接采用注解化的方式启动,底层会依赖于Spring/SpringMVC注解方式启动。

总结:SpringBoot底层基于Spring/SpringMVC注解化方式实现包装。

比如:

1.@RestController

2.@ComponentScan("com.mayikt.aop")

3. @Configuration

4. @Component

5. @Scheduled

6. @Value

7. @Bean

SpringIOC底层容器原理

Spring框架快速入门

Spring | Home spring的官网

Spring官方下载依赖jar包地址:

JFrog

本次课以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>
JDBCDAO模块(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.根据beanid获取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.获取<bean id=”” class=””/> 类的完整路径地址

3.使用到反射技术初始化对象

4.需要使用工厂模式封装初始化对象

IOC核心的接口

1. 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方法注入属性

1. 什么是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属性: 类的完整路径地址(类名称+包名称)

默认底层使用反射技术执行无参数构造函数

2. 基于xml方式注入属性

DI 依赖注入: 对象的属性注入值; (spring实现)

1. 第一种实现方式:基于对象属性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) {
this.orderId = orderId;
this.orderName = orderName;
}

@Override
public String toString() {
return "OrderEntity{" +
"orderId='" + orderId + '\'' +
", orderName='" + orderName + '\'' +
'}';
}
}

Xml配置文件

<bean id="orderEntity" class="com.mayikt.entity.OrderEntity">
<!--
<constructor-arg name="orderId" value="123456"></constructor-arg>
<constructor-arg name="orderName" value="蚂蚁课堂第八期订单"></constructor-arg>
-->
<constructor-arg index="0" value="123456"></constructor-arg>
<constructor-arg index="1" value="蚂蚁课堂第八期订单"></constructor-arg>
</bean>

<constructor-arg name 指定参数列表名称

<constructor-arg index 指定参数列表索引

p名称空间注入

1. 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"></bean>

2. 使用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="bookName" value="<<武汉>>"></property>
<property name="bookPrice">
<null></null>
</property>
</bean>

Cdata注入方式

<![CDATA[<<>>]]>

<bean id="bookEntity4" class="com.mayikt.entity.BookEntity">
<!-- <property name="bookName" value="<<武汉>>"></property> -->
<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() {
return memberDao;
}

public void setMemberDao(MemberDao memberDao) {
this.memberDao = memberDao;
}

public void addMember() {
System.out.println("<<<Service Service>>");
// 原始的方式
// MemberDao memberDao = new MemberDaoImpl();
// memberDao.addMember();
memberDao.addMember();
}
}

<?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">


<!--
注入useService
-->
<bean id="memberService" class="com.mayikt.service.MemberService">
<!-- 注入userDao
name 属性值: 类中属性的名称;
ref 创建MemberDaoImpl类的 beanid
-->
<property name="memberDao" ref="memberDao"></property>
</bean>
<bean id="memberDao" class="com.mayikt.dao.MemberDaoImpl"></bean>
</beans>

注入内部bean

1. 数据库表一对多或者一对一的关系

2. 部门--n多个员工 一对多

3. 站在员工角度考虑员工属于那个部门

4. 站在部门的角度考虑部门下n多个员工

1. 在数据库中表中有一对一一对多的关系;

2. 一对多关系;部门与员工 一个部门会有多个员工 一个员工属于一个部门;

3. 实体类之间表示一对多的关系;

实体类员工对象

public class EmpEntity {

private String name;
private Integer age;
/**
* 员工属于那个部门
*/
private DeptEntity deptEntity;
public void setName(String name) {
this.name = name;
}

public String getName() {
return name;
}

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}

public void setDeptEntity(DeptEntity deptEntity) {
this.deptEntity = deptEntity;
}

@Override
public String toString() {
return "EmpEntity{" +
"name='" + name + '\'' +
", age=" + age +
", deptEntity=" + deptEntity +
'}';
}
}

部门对象

public class DeptEntity {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}

@Override
public String toString() {
return "DeptEntity{" +
"name='" + name + '\'' +
'}';
}
}

Xml相关配置


<!--内部bean -->
<bean id="empEntity" class="com.mayikt.entity.EmpEntity">
<!--设置属性name/age -->
<property name="name" value="mayikt"></property>
<property name="age" value="21"></property>
<!-- 嵌入部门bean-->
<property name="deptEntity">
<bean id="deptEntity" class="com.mayikt.entity.DeptEntity">
<property name="name" value="教育部门"></property>
</bean>
</property>

</bean>

注入级联赋值

写法1

<bean id="empEntity" class="com.mayikt.entity.EmpEntity">
<!--两个属性-->
<property name="name" value="mayikt"></property>
<property name="addres" value="湖北省武汉市"></property>
<!--级联赋值-->
<property name="deptEntity" ref="deptEntity"></property>
</bean>
<bean id="deptEntity" class="com.mayikt.entity.DeptEntity">
<property name="name" value="教育部门"></property>
</bean>

写法2

<bean id="empEntity" class="com.mayikt.entity.EmpEntity">
<!--两个属性-->
<property name="name" value="mayikt"></property>
<property name="addres" value="湖北省武汉市"></property>
<!--级联赋值-->
<property name="deptEntity" ref="deptEntity"></property>
<property name="deptEntity.name" value="教育部门"></property>
</bean>
<bean id="deptEntity" class="com.mayikt.entity.DeptEntity">
</bean>

注意:需要在员工实体类新增:deptEntity get方法。

注入集合类型属性

1. 注入数组类型

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<String> list;
//3.Map
private Map<String,String> map;
//4.Set
private Set<String> set;

public void setArrays(String[] arrays) {
this.arrays = arrays;
}

public void setList(List<String> list) {
this.list = list;
}

public void setMap(Map<String, String> map) {
this.map = map;
}

public void setSet(Set<String> set) {
this.set = set;
}

@Override
public String toString() {
return "StuEntity{" +
"arrays=" + Arrays.toString(arrays) +
", list=" + list +
", map=" + map +
", set=" + set +
'}';
}
}

配置文件

<bean id="stuEntity" class="com.mayikt.entity.StuEntity">
<!--数组类型注入-->
<property name="arrays">
<array>
<value>mayikt01</value>
<value>mayikt02</value>
</array>
</property>
<!--list-->
<property name="list">
<list>
<value>语文</value>
<value>数学</value>
</list>
</property>
<!--Map-->
<property name="map">
<map>
<entry key="余胜军" value="23"></entry>
<entry key="小薇" value="25"></entry>
</map>
</property>
<!--Set-->
<property name="Set">
<set>
<value>01</value>
<value>02</value>
</set>
</property>
</bean>

集合类型为对象

private List<CourseEntity> courses;

public void setCourses(List<CourseEntity> courses) {
this.courses = courses;
}

public class CourseEntity {
private String name;

public void setName(String name) {
this.name = name;
}

@Override
public String toString() {
return "CourseEntity{" +
"name='" + name + '\'' +
'}';
}
}

<?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="stuEntity" class="com.mayikt.entity.StuEntity">
<!--对我们的list属性赋值-->
<property name="list">
<list>
<value>list01</value>
<value>list02</value>
</list>
</property>
<!--对我们的arrays属性赋值-->
<property name="arrays">
<array>
<value>mayikt01</value>
<value>mayikt02</value>
</array>
</property>
<!--对我们的map属性赋值-->
<property name="map">
<map>
<entry key="mayikt" value="余胜军"></entry>
<entry key="xiaowei" value="小薇"></entry>
</map>
</property>
<!--对我们的set属性赋值-->
<property name="set">
<set>
<value>list01</value>
<value>list02</value>
</set>
</property>
<property name="courses" >
<list>
<ref bean="courseEntity1"></ref>

集合注入部分提取公共

1. 需要先引入一个util名称空间

<?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: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">

2. 使用util标签 注入

<?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: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">
<value>mayikt01</value>
<value>mayikt02</value>
</util:list>
<bean id="stuEntity" class="com.mayikt.entity.StuEntity">
<property name="list" ref="list"></property>
</bean>
</beans>

IOC操作Bean的管理

1. 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<UserEntity> {
/**
* 定义返回bean
*
* @return
* @throws Exception
*/
public UserEntity getObject() throws Exception {
return new UserEntity();
}

public Class<?> getObjectType() {
return null;
}
}

public static void main(String[] args) {
ClassPathXmlApplicationContext app =
new ClassPathXmlApplicationContext("spring_08.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存在多个实例;

证明:如果是为单例,则两个对象地址都是一样的,

多例子对象则两个对象地址不一样。

单例配置:

<bean id="userEntity" class="com.mayikt.entity.UserEntity" scope="singleton"></bean>

默认就是为单例子;

多例配置:

<bean id="userEntity" class="com.mayikt.entity.UserEntity" scope="prototype"></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) {
System.out.println("[第二步]-set方法初始化属性---反射机制调用");
this.name = name;
}

/**
* 回调调用init初始化方法
*/
public void initMethod(){
System.out.println("[第三步]-回调调用init初始化方法");
}

/**
* destroyMethod
*/
public void destroyMethod(){
System.out.println("[第五步]-回调调用destroyMethod方法");
}
}

<bean id="memberEntity" class="com.mayikt.entity.MemberEntity" init-method="initMethod" destroy-method="destroyMethod">
<property name="name" value="mayikt"></property>
</bean>
<bean id="mayiktBeanPost" class="com.mayikt.bean.MayiktBeanPost"></bean>

import com.mayikt.entity.MemberEntity;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test07 {
public static void main(String[] args) {
ClassPathXmlApplicationContext app =
new ClassPathXmlApplicationContext("spring_07.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 {
System.out.println("在bean 初始化方法之后执行");
return bean;
}
}

<bean id="mayiktBeanPost" class="com.mayikt.bean.MayiktBeanPost"></bean>

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 {
System.out.println("调用该bean的 init方法之后");
return bean;
}

public int getOrder() {
return 1;
}
}

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 {
System.out.println("[MayiktBeanPost02:]调用该bean的 init方法之后");
return bean;
}

public int getOrder() {
return 0;
}
}

<!-- 后置处理器-->
<bean id="mayiktBeanPost" class="com.mayikt.bean.MayiktBeanPost"></bean>
<bean id="mayiktBeanPost02" class="com.mayikt.bean.MayiktBeanPost02"></bean>

实现Ordered接口 getOrder 值越小越优先加载

SpringBean的自动装配

什么是自动装配呢

根据装配的规则(属性的名称或者属性的类型)

Spring根据装配的规则自动为属性注入值。

1. 什么是自动装配

A. 根据指定装配规则(属性名称或者属性的类型),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"
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.根据属性的名称注入 beanid名称与属性的名称一致
2.根据属性的类型注入 bean的类型与属性类型一致
-->
<bean id="empEntity" class="com.mayikt.entity.EmpEntity" autowire="byType">

</bean>
<bean id="deptEntity" class="com.mayikt.entity.DeptEntity">
<property name="name" value="教育部门"></property>
</bean>

</beans>

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动态代理原理分析

1. 获取代理的生成的class文件

System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

//
// 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的动态代理不支持对实现类的代理,只支持接口的代理。

    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 OrderServiceImpl$$EnhancerByCGLIB$$1dd3a71c 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动态代理

Aop实现统一日志输出

aop实现统一日志输出

  • 21
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值