Spring5

Spring5课程介绍

  1. IOC容器;
    2. AOP面向切面编程;
    3. 声明事务;
    4. 注解的方式启动对我们后期学习SpringBoot有非常大帮助;
    5. 整合SpringMVC 和Mybatis;
    6. Spring5新特性;
    JDK最低版本要求1.8

    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接口实现了封装)

    Spring与SpringBoot关系

    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框架快速入门

    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依赖:

  1. <dependency>
  2. <groupId>org.springframework</groupId>
  3. <artifactId>spring-core</artifactId>
  4. <version>5.2.1.RELEASE</version>
  5. </dependency>

Spring-Beans

这个jar 文件是所有应用都要用到的,它包含访问配置文件、创建和管理bean 以及进行Inversion ofControl / Dependency Injection(IoC/DI)操作相关的所有类。如果应用只需基本的IoC/DI 支持,引入spring-core.jar 及spring-beans.jar 文件就可以了。
外部依赖spring-core,(CGLIB)。

  1. <dependency>
  2. <groupId>org.springframework</groupId>
  3. <artifactId>spring-beans</artifactId>
  4. <version>5.2.1.RELEASE</version>
  5. </dependency>

Spring Context
  1. <dependency>
  2. <groupId>org.springframework</groupId>
  3. <artifactId>spring-context</artifactId>
  4. <version>5.2.1.RELEASE</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.springframework</groupId>
  8. <artifactId>spring-context-support</artifactId>
  9. <version>5.2.1.RELEASE</version>
  10. </dependency>

Spring上下文是一个配置文件,向Spring框架提供上下文信息。Spring上下文包括企业服务,如JNDI、EJB、电子邮件、国际化、校验和调度功能。
Spring-Expression
模块提供了一个强大的表达式语言,用于在运行时查询和处理对象图。该语言支持设置和获取属性值;属性赋值,方法调用,访问数组的内容,收集和索引器,逻辑和算术运算,命名变量,并从Spring的IOC容器的名字对象检索,它也支持列表选择和投影以及常见的列表聚合。

  1. <dependency>
  2. <groupId>org.springframework</groupId>
  3. <artifactId>spring-expression</artifactId>
  4. <version>5.2.1.RELEASE</version>
  5. </dependency>

Spring AOP

通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring框架中。所以,可以很容易地使 Spring框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖 EJB 组件,就可以将声明性事务管理集成到应用程序中。

  1. <dependency>
  2. <groupId>org.springframework</groupId>
  3. <artifactId>spring-aop</artifactId>
  4. <version>5.2.1.RELEASE</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.springframework</groupId>
  8. <artifactId>spring-aspects</artifactId>
  9. <version>5.2.1.RELEASE</version>
  10. </dependency>

JDBC和DAO模块(Spring DAO)

JDBC、DAO的抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理,和不同数据库供应商所抛出的错误信息。异常层次结构简化了错误处理,并且极大的降低了需要编写的代码数量,比如打开和关闭链接。

  1. <dependency>
  2. <groupId>org.springframework</groupId>
  3. <artifactId>spring-tx</artifactId>
  4. <version>5.2.1.RELEASE</version>
  5. </dependency>

spring-transaction

以前是在这里org.springframework.transaction
为JDBC、Hibernate、JDO、JPA、Beans等提供的一致的声明式和编程式事务管理支持。

  1. <dependency>
  2. <groupId>org.springframework</groupId>
  3. <artifactId>spring-tx</artifactId>
  4. <version>5.2.1.RELEASE</version>
  5. </dependency>

Spring ORM

Spring框架插入了若干个ORM框架,从而提供了ORM对象的关系工具,其中包括了Hibernate、JDO和 IBatis SQL Map等,所有这些都遵从Spring的通用事物和DAO异常层次结构。

  1. <dependency>
  2. <groupId>org.springframework</groupId>
  3. <artifactId>spring-orm</artifactId>
  4. <version>5.2.1.RELEASE</version>
  5. </dependency>

Spring Web MVC

MVC框架是一个全功能的构建Web应用程序的MVC实现。通过策略接口,MVC框架变成为高度可配置的。MVC容纳了大量视图技术,其中包括JSP、POI等,模型来有JavaBean来构成,存放于m当中,而视图是一个街口,负责实现模型,控制器表示逻辑代码,由c的事情。Spring框架的功能可以用在任何J2EE服务器当中,大多数功能也适用于不受管理的环境。Spring的核心要点就是支持不绑定到特定J2EE服务的可重用业务和数据的访问的对象,毫无疑问这样的对象可以在不同的J2EE环境,独立应用程序和测试环境之间重用。

  1. <dependency>
  2. <groupId>org.springframework</groupId>
  3. <artifactId>spring-web</artifactId>
  4. <version>5.2.1.RELEASE</version>
  5. </dependency>

项目构建

Maven依赖
  1. <dependencies>
  2. <!--
  3. 这个jar 文件包含Spring 框架基本的核心工具类。Spring 其它组件要都要使用到这个包里的类,是其它组件的基本核心,当然你也可以在自己的应用系统中使用这些工具类。
  4. 外部依赖Commons Logging (Log4J)。
  5. -->
  6. <dependency>
  7. <groupId>org.springframework</groupId>
  8. <artifactId>spring-core</artifactId>
  9. <version>5.2.1.RELEASE</version>
  10. </dependency>
  11. <!--
  12. 这个jar 文件是所有应用都要用到的,它包含访问配置文件、创建和管理bean 以及进行Inversion ofControl / Dependency InjectionIoC/DI)操作相关的所有类。如果应用只需基本的IoC/DI 支持,引入spring-core.jar spring-beans.jar 文件就可以了。
  13. 外部依赖spring-core,(CGLIB)。
  14. -->
  15. <dependency>
  16. <groupId>org.springframework</groupId>
  17. <artifactId>spring-beans</artifactId>
  18. <version>5.2.1.RELEASE</version>
  19. </dependency>
  20. <!--
  21. 这个jar 文件为Spring 核心提供了大量扩展。可以找到使用Spring ApplicationContext特性时所需的全部类,JDNI 所需的全部类,instrumentation组件以及校验Validation 方面的相关类。
  22. 外部依赖spring-beans, (spring-aop)。
  23. -->
  24. <dependency>
  25. <groupId>org.springframework</groupId>
  26. <artifactId>spring-context</artifactId>
  27. <version>5.2.1.RELEASE</version>
  28. </dependency>
  29. </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"**>

  1. _<!--_ 配置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核心的接口

  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;

  1. **public **OrderEntity(String orderId, String orderName) {<br /> **this**.**orderId **= orderId;<br /> **this**.**orderName **= orderName;<br /> }
  2. @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=”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"**>
  1. 使用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;

  1. public MemberDao getMemberDao() {<br /> return memberDao;<br /> }
  2. public void setMemberDao(MemberDao memberDao) {<br /> this.memberDao = memberDao;<br /> }
  3. 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">
  4. _<!--_ 注入useService_ -->_ _<bean id="memberService" class="com.mayikt.service.MemberService"><br /> _<!-- 注入userDao_ name 属性值: 类中属性的名称;_ ref 创建MemberDaoImpl类的 beanid_ -->_ _<property name="memberDao" ref="memberDao"></property><br /> </bean><br /> <bean id="memberDao" class="com.mayikt.dao.MemberDaoImpl"></bean><br /></beans><br /><br /> |

| —- |

注入内部bean

  1. 数据库表一对多或者一对一的关系
    2. 部门—n多个员工 一对多
    3. 站在员工角度考虑员工属于那个部门
    4. 站在部门的角度考虑部门下n多个员工
  1. 在数据库中表中有一对一一对多的关系;
    2. 一对多关系;部门与员工 一个部门会有多个员工 一个员工属于一个部门;
    3. 实体类之间表示一对多的关系;

实体类员工对象

| public class EmpEntity {

  1. private String name;<br /> private Integer age;<br /> _/**_ * 员工属于那个部门_ */_ _private DeptEntity deptEntity;<br /> public void setName(String name) {<br /> this.name = name;<br /> }
  2. public String getName() {<br /> return name;<br /> }
  3. public Integer getAge() {<br /> return age;<br /> }
  4. public void setAge(Integer age) {<br /> this.age = age;<br /> }
  5. public void setDeptEntity(DeptEntity deptEntity) {<br /> this.deptEntity = deptEntity;<br /> }
  6. @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;
}

  1. @Override<br /> public String toString() {<br /> return "DeptEntity{" +<br /> "name='" + name + '\\'' +<br /> '}';<br /> }<br />}<br /> |

| —- |

Xml相关配置

|



_




| | —- |

注入级联赋值

写法1








写法2








注意:需要在员工实体类新增: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 list;
//3.Map _private Map map;
//4.Set_ _private Set set;

  1. public void setArrays(String[] arrays) {<br /> this.arrays = arrays;<br /> }
  2. public void setList(List<String> list) {<br /> this.list = list;<br /> }
  3. public void setMap(Map<String, String> map) {<br /> this.map = map;<br /> }
  4. public void setSet(Set<String> set) {<br /> this.set = set;<br /> }
  5. @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 /> |

| —- |

配置文件




mayikt01
mayikt02




语文
数学










01
02



集合类型为对象

| private List courses;
public void setCourses(List courses) {
this.courses = courses;
}

public class CourseEntity {
private String name;

  1. public void setName(String name) {<br /> this.name = name;<br /> }
  2. @Override<br /> public String toString() {<br /> return "CourseEntity{" +<br /> "name='" + name + '\\'' +<br /> '}';<br /> }<br />}<br /> |

| —- |

| <?_xml version=”1.0” encoding=”UTF-8”?> 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">

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

| —- |

集合注入部分提取公共

  1. 需要先引入一个util名称空间
<?_xml version=”1.0” encoding=”UTF-8”?> 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">
  1. 使用util标签 注入

| <?_xml version=”1.0” encoding=”UTF-8”?> 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">

  1. _<!-- 提取公共部分-->_ _<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的管理

  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 {
/** 定义返回bean_ * @return @throws Exception_ /_ _public UserEntity getObject() throws Exception {
return new UserEntity();
}

  1. 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(“[第一步]-无参构造函数被执行—-反射机制调用”);
}

  1. public void setName(String name) {<br /> System._out_.println("[第二步]-set方法初始化属性---反射机制调用");<br /> this.name = name;<br /> }
  2. _/**_ * 回调调用init初始化方法_ */_ _public void initMethod(){<br /> System._out_.println("[第三步]-回调调用init初始化方法");<br /> }
  3. _/**_ * 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;
}

  1. _/**_ * 调用初始化方法之后执行_ * @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;
}

  1. _/**_ * 调用初始化方法之后执行_ * @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 /> }
  2. 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;
}

  1. _/**_ * 调用初始化方法之后执行_ * @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 /> }
  2. public int getOrder() {<br /> return 0;<br /> }<br />}<br /> |

| —- |

_

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

SpringBean的自动装配

什么是自动装配呢
根据装配的规则(属性的名称或者属性的类型)
Spring根据装配的规则自动为属性注入值。

  1. 什么是自动装配
    A. 根据指定装配规则(属性名称或者属性的类型),spring自动
    将匹配属性的值注入。

| <?_xml version=”1.0” encoding=”UTF-8”?> 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">

  1. _<!-- 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">
  2. </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的引用,负责对真实主题角色的调用,并在真实主题角色处理前后做预处理和后处理。

代理模式创建方式

相关测试代码:

  1. package com.mayikt.service;
  2. /**
  3. * @author 余胜军
  4. * @ClassName OrderService
  5. * @qq 644064779
  6. * @addres www.mayikt.com
  7. * 微信:yushengjun644
  8. */
  9. public interface OrderService {
  10. /**
  11. * 添加订单数据
  12. */
  13. String addOrder(String orderName);
  14. }
  15. package com.mayikt.service.impl;
  16. import com.mayikt.service.OrderService;
  17. import lombok.extern.slf4j.Slf4j;
  18. @Slf4j
  19. public class OrderServiceImpl implements OrderService {
  20. @Override
  21. public String addOrder(String orderName) {
  22. log.info("<orderName:{}>", orderName);
  23. return "ok";
  24. }
  25. }

静态代理

基于接口实现方式

  1. package com.mayikt.proxy1;
  2. import com.mayikt.service.OrderService;
  3. import lombok.extern.slf4j.Slf4j;
  4. /**
  5. * @author 余胜军
  6. * @ClassName OrderServiceProxy
  7. * @qq 644064779
  8. * @addres www.mayikt.com
  9. * 微信:yushengjun644
  10. */
  11. @Slf4j
  12. public class OrderServiceProxy implements OrderService {
  13. private OrderService orderService;
  14. public OrderServiceProxy(OrderService orderService) {
  15. this.orderService = orderService;
  16. }
  17. @Override
  18. public String addOrder(String orderName) {
  19. // 目标方法前后处理操作
  20. log.info("<目标方法之前执行...>");
  21. String result = orderService.addOrder(orderName);
  22. log.info("<目标方法之后执行...>");
  23. return result;
  24. }
  25. }
  26. package com.mayikt.proxy1;
  27. import com.mayikt.service.impl.OrderServiceImpl;
  28. /**
  29. * @author 余胜军
  30. * @ClassName Test01
  31. * @qq 644064779
  32. * @addres www.mayikt.com
  33. * 微信:yushengjun644
  34. */
  35. public class Test01 {
  36. public static void main(String[] args) {
  37. OrderServiceProxy orderServiceProxy = new OrderServiceProxy(new OrderServiceImpl());
  38. String result = orderServiceProxy.addOrder("mayikt");
  39. System.out.println(result);
  40. }
  41. }

基于继承实现方式

  1. package com.mayikt.proxy2;
  2. import com.mayikt.service.impl.OrderServiceImpl;
  3. import lombok.extern.slf4j.Slf4j;
  4. /**
  5. * @author 余胜军
  6. * @ClassName OrderServiceProxy
  7. * @qq 644064779
  8. * @addres www.mayikt.com
  9. * 微信:yushengjun644
  10. */
  11. @Slf4j
  12. public class OrderServiceProxy extends OrderServiceImpl {
  13. @Override
  14. public String addOrder(String orderName) {
  15. // 目标方法前后处理操作
  16. log.info("<目标方法之前执行...>");
  17. String result = super.addOrder(orderName);
  18. log.info("<目标方法之后执行...>");
  19. return result;
  20. }
  21. }
  22. package com.mayikt.proxy2;
  23. /**
  24. * @author 余胜军
  25. * @ClassName Test01
  26. * @qq 644064779
  27. * @addres www.mayikt.com
  28. * 微信:yushengjun644
  29. */
  30. public class Test01 {
  31. public static void main(String[] args) {
  32. OrderServiceProxy orderServiceProxy = new OrderServiceProxy();
  33. String result = orderServiceProxy.addOrder("mayikt");
  34. System.out.println(result);
  35. }
  36. }

动态代理

动态代理是在实现阶段不用关心代理类,而在运行阶段才指定哪一个对象。
动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成 。
JDK动态代理的一般步骤如下:
1.创建被代理的接口和类;
2.实现InvocationHandler接口,对目标接口中声明的所有方法进行统一处理;
3.调用Proxy的静态方法,创建代理类并生成相应的代理对象;
实现原理:利用拦截器机制必须实现InvocationHandler接口中的invoke方法实现对
我们的目标方法增强。


JDK API动态代理用法

  1. package com.mayikt.proxy3;
  2. import lombok.extern.slf4j.Slf4j;
  3. import java.lang.reflect.InvocationHandler;
  4. import java.lang.reflect.Method;
  5. import java.lang.reflect.Proxy;
  6. /**
  7. * @author 余胜军
  8. * @ClassName JdkInvocationHandler
  9. * @qq 644064779
  10. * @addres www.mayikt.com
  11. * 微信:yushengjun644
  12. */
  13. @Slf4j
  14. public class JdkInvocationHandler implements InvocationHandler {
  15. /**
  16. * 目标对象
  17. */
  18. private Object target;
  19. public JdkInvocationHandler(Object target) {
  20. this.target = target;
  21. }
  22. @Override
  23. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  24. log.info("<jdk动态代理目标方法之前>,args:{}", args);
  25. Object result = method.invoke(target, args);
  26. log.info("<jdk动态代理目标方法之后,args:{}", args);
  27. return result;
  28. }
  29. public <T> T getProxy() {
  30. return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
  31. }
  32. }
  33. package com.mayikt.proxy3;
  34. import com.mayikt.service.OrderService;
  35. import com.mayikt.service.impl.OrderServiceImpl;
  36. /**
  37. * @author 余胜军
  38. * @ClassName Test01
  39. * @qq 644064779
  40. * @addres www.mayikt.com
  41. * 微信:yushengjun644
  42. */
  43. public class Test01 {
  44. public static void main(String[] args) {
  45. System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
  46. JdkInvocationHandler jdkInvocationHandler = new JdkInvocationHandler(new OrderServiceImpl());
  47. OrderService orderService = jdkInvocationHandler.getProxy();
  48. orderService.addOrder("mayikt");
  49. }
  50. }

动态代理与静态代理的区别

动态代理不需要写代理类对象,通过程序自动生成,而静态代理需要我们自己写代理类对象。

JDK动态代理原理分析

  1. 获取代理的生成的class文件
    System.getProperties().put(“sun.misc.ProxyGenerator.saveGeneratedFiles”, “true”);
    image.png ```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;

  1. public $Proxy0(InvocationHandler var1) throws {
  2. super(var1);
  3. }
  4. public final boolean equals(Object var1) throws {
  5. try {
  6. return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
  7. } catch (RuntimeException | Error var3) {
  8. throw var3;
  9. } catch (Throwable var4) {
  10. throw new UndeclaredThrowableException(var4);
  11. }
  12. }
  13. public final String addOrder(String var1) throws {
  14. try {
  15. return (String)super.h.invoke(this, m3, new Object[]{var1});
  16. } catch (RuntimeException | Error var3) {
  17. throw var3;
  18. } catch (Throwable var4) {
  19. throw new UndeclaredThrowableException(var4);
  20. }
  21. }
  22. public final String toString() throws {
  23. try {
  24. return (String)super.h.invoke(this, m2, (Object[])null);
  25. } catch (RuntimeException | Error var2) {
  26. throw var2;
  27. } catch (Throwable var3) {
  28. throw new UndeclaredThrowableException(var3);
  29. }
  30. }
  31. public final int hashCode() throws {
  32. try {
  33. return (Integer)super.h.invoke(this, m0, (Object[])null);
  34. } catch (RuntimeException | Error var2) {
  35. throw var2;
  36. } catch (Throwable var3) {
  37. throw new UndeclaredThrowableException(var3);
  38. }
  39. }
  40. static {
  41. try {
  42. m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
  43. m3 = Class.forName("com.mayikt.service.OrderService").getMethod("addOrder", Class.forName("java.lang.String"));
  44. m2 = Class.forName("java.lang.Object").getMethod("toString");
  45. m0 = Class.forName("java.lang.Object").getMethod("hashCode");
  46. } catch (NoSuchMethodException var2) {
  47. throw new NoSuchMethodError(var2.getMessage());
  48. } catch (ClassNotFoundException var3) {
  49. throw new NoClassDefFoundError(var3.getMessage());
  50. }
  51. }

}

注意:继承了Proxy类,实现了代理的接口,由于java不能多继承,这里已经继承了Proxy类了,不能再继承其他的类,所以JDK的动态代理不支持对实现类的代理,只支持接口的代理。

  1. ```java
  2. public static void main(String[] args) {
  3. $Proxy0 $Proxy0 = new $Proxy0(new JdkInvocationHandler(new OrderServiceImpl()));
  4. $Proxy0.addOrder("mayikt");
  5. }
  1. public <T> T getProxy() {
  2. return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
  3. this);
  4. 生成代理类时 会传递我们目标对象实现哪些接口
  5. target.getClass().getInterfaces()
  6. 如果我们目标对象没有实现接口 jdk动态代理生成代理类 也没有实现接口
  7. 使用jdk动态代理时 注意 让目标对象实现接口, 生成代理类时 实现目标对象的接口
  8. 方便可以使用接口调用目标对象的方法

1.执行到我们 代理类中$Proxy0.addOrder()
2.执行到我们MayiktInvocationHandler.invoke

  1. public final String addOrder(String var1) {
  2. try {
  3. return (String) super.h.invoke(this, m3, new Object[]{var1});
  4. } catch (RuntimeException | Error var3) {
  5. throw var3;
  6. } catch (Throwable var4) {
  7. throw new UndeclaredThrowableException(var4);
  8. }
  9. }

3.执行到我们MayiktInvocationHandler.invoke 在根据java反射机制 传递目标对象 调用目标方法

mybatis mapper接口分析

在mybatis mapper 是一个接口为何可以调用的呢?底层其实就是基于JDK动态代理实现。
相关代码:

  1. package com.mayikt.mybatis.ext;
  2. import org.springframework.stereotype.Indexed;
  3. import java.lang.annotation.*;
  4. /**
  5. * @author 余胜军
  6. * @ClassName MayiktInsert
  7. * @qq 644064779
  8. * @addres www.mayikt.com
  9. * 微信:yushengjun644
  10. */
  11. @Target({ElementType.METHOD})
  12. @Retention(RetentionPolicy.RUNTIME)
  13. @Documented
  14. @Indexed
  15. public @interface MayiktInsert {
  16. String value();
  17. }
  18. package com.mayikt.mybatis;
  19. import com.mayikt.mybatis.ext.MayiktInsert;
  20. import com.mayikt.utils.MayiktJdbcUtils;
  21. import org.apache.commons.lang.StringUtils;
  22. import java.lang.reflect.InvocationHandler;
  23. import java.lang.reflect.Method;
  24. import java.lang.reflect.Proxy;
  25. import java.sql.Connection;
  26. import java.sql.PreparedStatement;
  27. /**
  28. * @author 余胜军
  29. * @ClassName MybatisJdkInvocationHandler
  30. * @qq 644064779
  31. * @addres www.mayikt.com
  32. * 微信:yushengjun644
  33. */
  34. public class MybatisJdkInvocationHandler implements InvocationHandler {
  35. private Class mapperClass;
  36. public MybatisJdkInvocationHandler(Class mapperClass) {
  37. this.mapperClass = mapperClass;
  38. }
  39. @Override
  40. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  41. // 使用java反射技术获取该方法上的注解
  42. MayiktInsert declaredAnnotation = method.getDeclaredAnnotation(MayiktInsert.class);
  43. String insertSql = declaredAnnotation.value();
  44. if (StringUtils.isEmpty(insertSql)) {
  45. return null;
  46. }
  47. // 执行该sql语句
  48. Connection connection = MayiktJdbcUtils.getConnection();
  49. PreparedStatement preparedStatement = connection.prepareStatement(insertSql);
  50. int result = preparedStatement.executeUpdate();
  51. return result;
  52. }
  53. public <T> T getProxy() {
  54. return (T) Proxy.newProxyInstance(mapperClass.getClassLoader(), new Class[]{mapperClass}, this);
  55. }
  56. }
  57. package com.mayikt.mybatis;
  58. import com.mayikt.mybatis.ext.MayiktInsert;
  59. /**
  60. * @author 余胜军
  61. * @ClassName UserMapper
  62. * @qq 644064779
  63. * @addres www.mayikt.com
  64. * 微信:yushengjun644
  65. */
  66. public interface UserMapper {
  67. @MayiktInsert("INSERT INTO `mayikt`.`mayikt_users` (`id`, `name`, `age`) VALUES (null, 'wangmazi', NULL);")
  68. int addUser();
  69. }
  70. package com.mayikt.mybatis;
  71. /**
  72. * @author 余胜军
  73. * @ClassName Test01
  74. * @qq 644064779
  75. * @addres www.mayikt.com
  76. * 微信:yushengjun644
  77. */
  78. public class Test01 {
  79. public static void main(String[] args) {
  80. System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
  81. UserMapper userMapper = MapperProxy.getUserMapper(UserMapper.class);
  82. int result = userMapper.addUser();
  83. System.out.println(result);
  84. }
  85. }
  86. package com.mayikt.mybatis;
  87. /**
  88. * @author 余胜军
  89. * @ClassName MapperProxy
  90. * @qq 644064779
  91. * @addres www.mayikt.com
  92. * 微信:yushengjun644
  93. */
  94. public class MapperProxy {
  95. public static UserMapper getUserMapper(Class mapperClass) {
  96. return new MybatisInvocationHandler(mapperClass).getProxy();
  97. }
  98. public static void main(String[] args) {
  99. // 将jdk动态生成好的 class 存放本地
  100. System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
  101. UserMapper userMapper = MapperProxy.getUserMapper(UserMapper.class);
  102. int i = userMapper.addUser();
  103. System.out.println(i);
  104. }
  105. }

mayikt-designmode.rar

什么是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基本用法

  1. <dependencies>
  2. <dependency>
  3. <groupId>cglib</groupId>
  4. <artifactId>cglib</artifactId>
  5. <version>3.2.12</version>
  6. </dependency>
  7. </dependencies>

实现MethodInterceptor接口的intercept方法后,所有生成的代理方法都调用这个方法。
intercept方法的具体参数有
obj 目标类的实例
1. method 目标方法实例(通过反射获取的目标方法实例)
2. args 目标方法的参数
3. proxy 代理类的实例
该方法的返回值就是目标方法的返回值。

  1. package com.mayikt.service;
  2. /**
  3. * @author 余胜军
  4. * @ClassName OrderService
  5. * @qq 644064779
  6. * @addres www.mayikt.com
  7. * 微信:yushengjun644
  8. */
  9. public interface OrderService {
  10. /**
  11. * 添加订单数据
  12. */
  13. String addOrder(String orderName);
  14. }
  15. package com.mayikt.service.impl;
  16. import com.mayikt.service.OrderService;
  17. import lombok.extern.slf4j.Slf4j;
  18. /**
  19. * @author 余胜军
  20. * @ClassName OrderServiceImpl
  21. * @qq 644064779
  22. * @addres www.mayikt.com
  23. * 微信:yushengjun644
  24. */
  25. @Slf4j
  26. public class OrderServiceImpl implements OrderService {
  27. // @Override
  28. public String addOrder(String orderName) {
  29. log.info("<orderName:{}>", orderName);
  30. // addorder相关的事情
  31. return "ok";
  32. }
  33. }
  34. package com.mayikt.cglib;
  35. import lombok.extern.slf4j.Slf4j;
  36. import net.sf.cglib.proxy.MethodInterceptor;
  37. import net.sf.cglib.proxy.MethodProxy;
  38. import java.lang.reflect.Method;
  39. /**
  40. * @author 余胜军
  41. * @ClassName MayiktCglibMethodInterceptor
  42. * @qq 644064779
  43. * @addres www.mayikt.com
  44. * 微信:yushengjun644
  45. */
  46. @Slf4j
  47. public class MayiktCglibMethodInterceptor implements MethodInterceptor {
  48. @Override
  49. public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
  50. log.info("<目标方法之前开始执行....>");
  51. // Object result = method.invoke(obj, args);
  52. Object result = proxy.invokeSuper(obj, args);
  53. log.info("<目标方法之后开始执行....>");
  54. return result;
  55. }
  56. }
  57. package com.mayikt.cglib;
  58. import com.mayikt.service.impl.OrderServiceImpl;
  59. import net.sf.cglib.core.DebuggingClassWriter;
  60. import net.sf.cglib.proxy.Enhancer;
  61. public class Test01 {
  62. public static void main(String[] args) {
  63. System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\code\\cglib");
  64. MayiktCglibMethodInterceptor mayiktCglibMethodInterceptor = new MayiktCglibMethodInterceptor();
  65. Enhancer enhancer = new Enhancer();
  66. // 设置代理
  67. enhancer.setSuperclass(OrderServiceImpl.class);
  68. // 设置cglib 回调类
  69. enhancer.setCallback(mayiktCglibMethodInterceptor);
  70. // 创建cglib代理类
  71. OrderServiceImpl orderServiceImpl = (OrderServiceImpl) enhancer.create();
  72. String result = orderServiceImpl.addOrder("mayikt");
  73. System.out.println(result);
  74. }
  75. }

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依赖

  1. <!-- aspectj支持 -->
  2. <dependency>
  3. <groupId>org.aspectj</groupId>
  4. <artifactId>aspectjrt</artifactId>
  5. <version>1.8.9</version>
  6. </dependency>
  7. <dependency>
  8. <groupId>org.apache.geronimo.bundles</groupId>
  9. <artifactId>aspectjweaver</artifactId>
  10. <version>1.6.8_2</version>
  11. </dependency>
  12. <dependency>
  13. <groupId>org.springframework</groupId>
  14. <artifactId>spring-aop</artifactId>
  15. <version>5.2.1.RELEASE</version>
  16. </dependency>

切入点表达式

具体那个类中的那个方法来实现增强
需要描述 该类中哪些方法是需要被增强——-切入点规则
image.png
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..*(..));

切入点表达式

测试代码

  1. package com.mayikt.service;
  2. import org.springframework.stereotype.Component;
  3. /**
  4. * @author 余胜军
  5. * @ClassName MayiktService
  6. * @qq 644064779
  7. * @addres www.mayikt.com
  8. * 微信:yushengjun644
  9. */
  10. @Component
  11. public class MayiktService {
  12. public String addMayikt() {
  13. System.out.println("addMayikt...");
  14. return "ok";
  15. }
  16. }
  17. package com.mayikt.proxy;
  18. import org.aspectj.lang.ProceedingJoinPoint;
  19. import org.aspectj.lang.annotation.*;
  20. import org.springframework.stereotype.Component;
  21. /**
  22. * @author 余胜军
  23. * @ClassName UserProxy
  24. * @qq 644064779
  25. * @addres www.mayikt.com
  26. * 微信:yushengjun644
  27. */
  28. @Component
  29. @Aspect// aop 代理
  30. public class UserProxy {
  31. /**
  32. * 前置通知
  33. */
  34. @Before("execution(* com.mayikt.service.MayiktService.addMayikt(..));")
  35. public void before() {
  36. System.out.println("前置通知...");
  37. }
  38. /**
  39. * 后置通知
  40. */
  41. @After("execution(* com.mayikt.service.MayiktService.addMayikt(..));")
  42. public void after() {
  43. System.out.println("后通知...");
  44. }
  45. /**
  46. * 环绕通知
  47. */
  48. @Around(value = "execution(* com.mayikt.service.MayiktService.addMayikt(..));")
  49. public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
  50. System.out.println("环绕通知...");
  51. System.out.println("目标方法之前开始执行...");
  52. Object result = proceedingJoinPoint.proceed();
  53. System.out.println("目标方法之后开始执行...");
  54. return result;
  55. }
  56. //@AfterReturning表达后置通知/返回通知,表达方法返回结果之后执行
  57. @AfterReturning(value = "execution(* com.mayikt.service.MayiktService.addMayikt(..));")
  58. public void afterReturning() {
  59. System.out.println("afterReturning");
  60. }
  61. //@AfterThrowing表达异常通知
  62. @AfterThrowing(value = "execution(* com.mayikt.service.MayiktService.addMayikt(..));")
  63. public void afterThrowing() {
  64. System.out.println("afterThrowing");
  65. }
  66. }

开启springaop

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xmlns:aop="http://www.springframework.org/schema/aop"
  6. xsi:schemaLocation="http://www.springframework.org/schema/beans
  7. http://www.springframework.org/schema/beans/spring-beans.xsd
  8. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
  9. http://www.springframework.org/schema/aop
  10. http://www.springframework.org/schema/aop/spring-aop.xsd
  11. ">
  12. <!--开启注解方式 -->
  13. <context:component-scan base-package="com.mayikt"></context:component-scan>
  14. <!--开启 aspectj 生成代理-->
  15. <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
  16. </beans>

  1. ClassPathXmlApplicationContext app =
  2. new ClassPathXmlApplicationContext("spring_07.xml");
  3. MayiktService mayiktService = app.getBean("mayiktService", MayiktService.class);
  4. mayiktService.addMayikt();

spring框架种使用 cglib?jdk动态代理?

spring aop 底层基于 代理封装?
如果我们 被代理类 没有实现接口的情况下 则使用 cglib动态代理
如果我们被代理类 有实现接口的情况下 则使用 jdk动态代理
image.png

image.png

Aop实现统一日志输出

aop实现统一日志输出