【Spring 知识宝典】 控制反转IOC 依赖注入DI 装配 代理 AOP 整合MyBatis 声明式事务

6.3.3、P和C的区别

  • 相同点

  • 都要在头文件中加入约束

  • 都可以对属性注入

  • 不同点

  • P 为属性简称,不需要有参构造器,相当于Set方法注入

  • C 为构造器简称,必须要有参构造器,相当于构造器注入

6.4、Bean的作用域


| 类别 | 说明 |

| — | — |

| singleton | 单例模式。使用 singleton 定义的 Bean 在 Spring 容器中只有一个实例,这也是 Bean 默认的作用域 |

| prototype | 原型模式,或多例模式。每次通过 Spring 容器获取 prototype 定义的 Bean 时,容器都将创建一个新的 Bean 实例。 |

| request | 在一次 HTTP 请求中,容器会返回该 Bean 的同一个实例。而对不同的 HTTP 请求,会返回不同的实例,该作用域仅在当前 HTTP Request 内有效。 |

| session | 在一次 HTTP Session 中,容器会返回该 Bean 的同一个实例。而对不同的 HTTP 请求,会返回不同的实例,该作用域仅在当前 HTTP Session 内有效。 |

| global session | 在一个全局的 HTTP Session 中,容器会返回该 Bean 的同一个实例。该作用域仅在使用 portlet context 时有效。 |

| websocket | websocket是一种应用层的通信协议,它提供应用层的全双工通信。若一个bean的作用域为websocket,则只作用于一次websocket通信,若连接被释放,则bean自然也会被销毁。 |

6.4.1、singleton

singleton(单例)是Spring中bean默认的作用域。若一个bean的作用域是单例的,那么每个IoC容器只会创建这个bean的一个实例对象。所有对这个bean的依赖,以及获取这个bean的代码,拿到的都是同一个bean实例。Spring容器在创建这个bean后,会将它缓存在容器中(实际上是放在一个ConcurrentHashMap中)。Spring中的单例bean不是线程安全的,所以只有在我们只关注bean能够提供的功能,而不在意它的状态(属性)时,才应该使用这个作用域

ServiceImpl_1、ServiceImpl_2 是同一个类的两个不同的对象,并且都是单例的

6.4.2、prototype

prototype可以理解为多例。若一个bean的作用域是prototype,那么Spring容器并不会缓存创建的bean,程序中对这个bean的每一次获取,容器都会重新实例化一个bean对象。通常,如果我们需要使用bean的状态(属性),且这个状态是会改变的,那么我们就可以将它配置为这个作用域,以解决线程安全的问题。因为对于单例bean来说,多个线程共享它的可变属性,会存在线程安全问题。

7、Bean的装配(注入)

=============

7.1、场景


Cat.java

public class Cat {

public void shout(){

System.out.println(“猫叫:喵喵~~~”);

}

}

Dog.java

public class Dog {

public void shout(){

System.out.println(“狗叫:汪汪~~~”);

}

}

User.java

public class User {

private Cat cat;

private Dog dog;

private String name;

public Cat getCat() {

return cat;

}

public void setCat(Cat cat) {

this.cat = cat;

}

public Dog getDog() {

return dog;

}

public void setDog(Dog dog) {

this.dog = dog;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

beans.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">

测试

public class MyTest {

@Test

public void test() {

ApplicationContext context = new ClassPathXmlApplicationContext(“beans.xml”);

User user = context.getBean(“user”, User.class);

System.out.println(“我是”+user.getName()+“,我的宠物”);

user.getCat().shout();

user.getDog().shout();

}

}

7.2、xml中手动配置


必须要有set方法

7.3、xml中自动装配autowire


必须要有set方法

7.3.1、byName自动装配

需要装配的bean的名称,必须和set方法后面的名称一致。

bean的id,name,alias别名中有一个和set方法后的名称一致即可

如 id=“cat” ,

id=“cat111” name=“cat cat222 , cat333 ; cat444”

alias name=“cat2” alias=“cat”

setCat()

7.3.2、byType自动装配

只要bean的类型一致就可以。id、name、alias即使没有也可以。

使用autowire byType首先需要保证:同一类型的对象,在spring容器中唯一。

如果不唯一,会报不唯一的异常。

NoUniqueBeanDefinitionException

7.4、在类中用注解自动装配


jdk1.5开始支持注解,spring2.5开始全面支持注解。

7.4.1、准备工作

  • 在beans配置文件中引入context文件头

xmlns:context=“http://www.springframework.org/schema/context”

http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context.xsd

  • 开启注解支持!

context:annotation-config/

7.4.2、@Autowired

  • @Autowired 是属于spring规范

  • @Autowired是按类型自动装配的,不支持名称匹配

  • 如果要按名称匹配,需加上@Qualifier

  • 可以省略set方法。前提是这个自动装配的属性在IOC容器中存在,且符合名字byName

  • 不建议使用字段注入。应在set方法上注入。

  • 在spring4之后,想要使用注解形式,必须得要引入aop的包

测试

将User类中的set方法去掉,使用@Autowired注解

public class User {

@Autowired

private Cat cat;

@Autowired

private Dog dog;

private String name;

public Cat getCat() {

return cat;

}

public Dog getDog() {

return dog;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

}

beans.xml

因为是按类型装配的,所以被装配的bean(如Cat、Dog)可以省去id

context:annotation-config/

测试通过

注:

  • @Autowired(required=false) 说明:false,对象可以为null;true,必须存对象,不能为null。

//如果允许对象为null,设置required = false,默认为true

@Autowired(required = false)

private Cat cat;

  • @Autowired是根据类型自动装配的,加上@Qualifier则可以根据byName的方式自动装配

  • @Qualifier不能单独使用。

@Autowired

@Qualifier(value = “cat2”)

private Cat cat;

@Autowired

@Qualifier(value = “dog2”)

private Dog dog;

@Nullable 如果字段标记了这个注解,说明这个字段可以是null

7.4.3、@Resource

  • @Resource 是属于J2EE规范

  • @Resource先按该属性进行byName方式查找装配;

  • 其次再进行默认的byName方式进行装配;

  • 如果以上都不成功,则按byType的方式自动装配。

  • 都不成功,则报异常。

public class User {

@Resource(name = “cat2”)

private Cat cat;

@Resource

private Dog dog;

private String str;

}

7.4.4、@Autowired与@Resource比较

  • 相同点

  • 都是注解方式注入对象,即装配bean

  • 都可以写在字段上,或写在set方法上

  • set方法可省略

  • 两种方式如果都显式的指定按名称装配,就只会按名称进行装配,装配不成功就直接报错。【@Autowired中@Qualifier(value = “cat2”)、@Resource(name=“cat2”)】

  • 不同点

  • @Autowired 属于spring规范

  • @Resource 属于J2EE规范

  • @Autowired 默认按类型byType装配

默认情况下必须要求依赖对象存在,如果要允许null 值,可以设置它的required属性为false,如:@Autowired(required=false) ,如果我们想使用名称装配可以结合@Qualifier注解进行使用

  • @Resource 默认按名称byName装配,如果找不到名称,就按类型byType装配

名称可以通过name属性进行指定。如果没有指定name属性,当注解写在字段上时,默认取字段名进行按照名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。

7.4.5、注解开发基本流程

要实现bean的自动配置,需要

  • 先配置包的自动扫描

  • 在bean类中加@Component注解,(或者衍生注解:@Controller、@Service、@Repository)

7.4.5.1、配置要扫描的包

context:annotation-config/

<context:component-scan base-package=“com.ajun.pojo”/>

7.4.5.2、添加注解@Component

在类上添加@Component之后才能被扫描到。不添加的话就是普通类。

@Component(“user”)

// 相当于配置文件中

public class User {

public String name = “秦疆”;

}

  • 测试

@Test

public void test1(){

ApplicationContext context = new ClassPathXmlApplicationContext(“beans.xml”);

User user = context.getBean(“user”, User.class);

System.out.println(user.name);

}

7.4.5.3、用注解注入属性

  • 不用set方法。直接在属性名上添加@value(“值”)。此时可以省略set方法。

@Value(“Ajun”)

public String name;

  • 如果提供了set方法,在set方法上添加@value(“值”)

public String name;

@Value(“Ajun”)

public void setName(String name) {

this.name = name;

}

7.4.5.4、Bean的衍生注解

为了更好的进行分层,Spring可以使用其它三个注解,功能一样,目前使用哪一个功能都一样。

  • @Controller:web层

  • @Service:service层

  • @Repository:dao层

写上这些注解,就相当于将这个类交给Spring管理装配了!

7.4.5.5、作用域@scope

  • singleton:默认的,Spring会采用单例模式创建这个对象。关闭工厂 ,所有的对象都会销毁。

  • prototype:多例模式。关闭工厂 ,所有的对象不会销毁。内部的垃圾回收机制会回收

@Component(value = “user”)

@Scope(“singleton”)

//相当于配置文件中

public class User {

public String name;

@Value(“hello”)

public void setName(String name) {

this.name = name;

}

}

7.5、XML与注解的比较


XML与注解比较

  • XML:可以适用任何场景 ,结构清晰,维护方便

  • 注解:不是自己提供的类使用不了,开发简单方便

xml与注解整合开发 :【推荐最佳实践】

  • xml管理Bean

  • 注解完成属性注入

  • 使用过程中, 可以不用扫描,扫描是为了类上的注解

context:annotation-config/

作用:

  • 进行注解驱动注册,从而使注解生效

  • 用于激活那些已经在spring容器里注册过的bean上面的注解,也就是显示的向Spring注册

  • 如果不扫描包,就需要手动配置bean

  • 如果不加注解驱动,注解无效,则注入的值为null!

7.6、java中显式配置


JavaConfig 原来是 Spring 的一个子项目,它通过 Java 类的方式提供 Bean 的定义信息,在 Spring4 的版本, JavaConfig 已正式成为 Spring4 的核心功能 。

关于这种Java类的配置方式,在之后的SpringBoot 和 SpringCloud中还会大量看到

测试:

1、编写一个实体类,Dog

@Component

//将这个类标注为Spring的一个组件,放到容器中!

public class Dog {

public String name = “dog”;

}

2、新建一个config配置包,编写一个MyConfig配置类

@Configuration

//代表这是一个配置类

public class MyConfig {

@Bean

//通过方法注册一个bean,这里的返回值就是Bean的类型,方法名就是bean的id!

public Dog dog(){

return new Dog();

}

}

3、测试

@Test

public void test2(){

ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);

Dog dog = context.getBean(“dog”,Dog.class);

System.out.println(dog.name);

}

4、成功输出结果!

导入其他配置如何做呢?

1、我们再编写一个配置类!

@Configuration

//代表这是一个配置类

public class MyConfig2 {

}

2、在之前的配置类中我们来选择导入这个配置类

@Configuration

@Import(MyConfig2.class)

//导入合并其他配置类,类似于配置文件中的 import 标签

public class MyConfig {

@Bean

public Dog dog(){

return new Dog();

}

}

8、代理模式

======

8.1、静态代理


8.1.1、案例图

8.1.2、角色分析

  • 抽象角色(Rent) : 一般使用接口或者抽象类来实现

//租房接口

public interface Rent {

public void rent();

}

  • 真实角色(Host) : 被代理的角色

//房东

public class Host implements Rent{

@Override

public void rent() {

System.out.println(“房东出租房子”);

}

}

  • 代理角色(Proxy) : 代理真实角色 ; 代理真实角色后 , 一般会做一些附属的操作

//中介

public class Proxy implements Rent {

private Host host;

public void setHost(Host host) {

this.host = host;

}

@Override

public void rent() {

seeHorse();

heTong();

fare();

host.rent();

}

//看房

private void seeHorse(){

System.out.println(“中介带看房”);

}

//签合同

private void heTong(){

System.out.println(“与中介签合同”);

}

//收费

private void fare(){

System.out.println(“收费:房租和中介费”);

}

}

  • 客户(Client) : 使用代理角色来进行一些操作

//客户租房

public class Client {

public static void main(String[] args) {

Host host = new Host();

//host.rent();

Proxy proxy = new Proxy();

proxy.setHost(host);

proxy.rent();

}

}

分析:在这个过程中,你直接接触的就是中介,就如同现实生活中的样子,你看不到房东,但是你依旧租到了房东的房子通过代理,这就是所谓的代理模式,程序源自于生活,所以学编程的人,一般能够更加抽象的看待生活中发生的事情。

8.1.3、优点

  • 可以使得我们的真实角色更加纯粹 . 不再去关注一些公共的事情 .

  • 公共的业务由代理来完成 . 实现了业务的分工 ,

  • 公共业务发生扩展时变得更加集中和方便 .

8.1.4、缺点

  • 类多了 , 多了代理类 , 工作量变大了 . 开发效率降低

8.1.5、深入理解

增删改查添加日志功能

  • 抽象角色 (接口)

UserService.java

//抽象角色:增删改查业务

public interface UserService {

void add();

void delete();

void update();

void query();

}

  • 实现类

UserServiceImpl.java

//真实对象,完成增删改查操作的人

public class UserServiceImpl implements UserService {

public void add() {

System.out.println(“增加了一个用户”);

}

public void delete() {

System.out.println(“删除了一个用户”);

}

public void update() {

System.out.println(“更新了一个用户”);

}

public void query() {

System.out.println(“查询了一个用户”);

}

}

  • 代理类

UserServiceProxy.java

//代理角色,在这里面增加日志的实现

public class UserServiceProxy implements UserService {

private UserServiceImpl userService;

public void setUserService(UserServiceImpl userService) {

this.userService = userService;

}

public void add() {

log(“add”);

userService.add();

}

public void delete() {

log(“delete”);

userService.delete();

}

public void update() {

log(“update”);

userService.update();

}

public void query() {

log(“query”);

userService.query();

}

public void log(String msg){

System.out.println(“执行了”+msg+“方法”);

}

}

  • 测试

public class Client {

public static void main(String[] args) {

//真实业务

UserServiceImpl userService = new UserServiceImpl();

//代理类

UserServiceProxy proxy = new UserServiceProxy();

//使用代理类实现日志功能!

proxy.setUserService(userService);

proxy.add();

}

}

总结

在不改变原有代码的情况下,实现了对原有功能的增强(添加日志功能),这是AOP中最核心的思想

8.2、动态代理


8.2.1、概述

动态代理就是动态生成代理类

  • 动态代理的角色和静态代理的一样 .

  • 动态代理的代理类是动态生成的 . 静态代理的代理类是我们提前写好的

  • 动态代理分为两类 : 一类是基于接口动态代理 , 一类是基于类的动态代理

  • 基于接口的动态代理----JDK动态代理

  • 基于类的动态代理–cglib

  • 现在用的比较多的是 javassist 来生成动态代理 . 百度一下javassist

8.2.2、JDK动态代理剖析

JDK的动态代理需要了解两个类

核心 : InvocationHandler 和 Proxy

1、InvocationHandler 调用处理程序

Object invoke(Object proxy, 方法 method, Object[] args);

//参数

//proxy - 调用该方法的代理实例

//method -所述方法对应于调用代理实例上的接口方法的实例。方法对象的声明类将是该方法声明的接口,它可以是代理类继承该方法的代理接口的超级接口。

//args -包含的方法调用传递代理实例的参数值的对象的阵列,或null如果接口方法没有参数。原始类型的参数包含在适当的原始包装器类的实例中,例如java.lang.Integer或java.lang.Boolean 。

2、Proxy 代理

//生成代理类

public Object getProxy(){

return Proxy.newProxyInstance(

this.getClass().getClassLoader(),

rent.getClass().getInterfaces(),

this

);

}

8.2.3、角色分析

抽象角色 和 真实角色 与之前的静态代理一样!

Rent . java 即抽象角色

//抽象角色:租房

public interface Rent {

public void rent();

}

Host . java 即真实角色

//真实角色: 房东

public class Host implements Rent{

@Override

public void rent() {

System.out.println(“房东出租房屋”);

}

}

ProxyInvocationHandler. java 即代理角色

public class ProxyInvocationHandler implements InvocationHandler {

//要代理的抽象角色

//接口类型:实现该接口的类都可以代理

private Rent rent;

public void setRent(Rent rent) {

this.rent = rent;

}

//生成代理类,重点是第二个参数,获取要代理的抽象角色!之前都是一个角色,现在可以代理一类角色

public Object getProxy(){

return Proxy.newProxyInstance(

this.getClass().getClassLoader(), //类加载器

rent.getClass().getInterfaces(), //要代理的接口列表

this //InvocationHandler 调用处理程序,就是当前类本身

);

}

// proxy : 代理类

// method : 代理类的调用处理程序的方法对象.

// 处理代理实例上的方法调用并返回结果

@Override

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

seeHouse();

//核心:本质利用反射实现!

Object invoke = method.invoke(rent, args);

fare();

return invoke;

}

//看房

public void seeHouse(){

System.out.println(“带房客看房”);

}

//收中介费

public void fare(){

System.out.println(“收中介费”);

}

}

Client . java

//租客

public class Client {

public static void main(String[] args) {

Host host = new Host();

ProxyInvocationHandler pih = new ProxyInvocationHandler();

pih.setRent(host);

Rent proxy = (Rent) pih.getProxy();

proxy.rent();

}

}

核心:一个动态代理 , 一般代理某一类业务 , 可以代理多个类(都实现某个接口),代理的是接口!

8.2.4、优点

静态代理有的它都有,静态代理没有的,它也有!

  • 可以使得我们的真实角色更加纯粹 . 不再去关注一些公共的事情 .

  • 公共的业务由代理来完成 . 实现了业务的分工 ,

  • 公共业务发生扩展时变得更加集中和方便 .

  • 一个动态代理 , 一般代理某一类业务

  • 一个动态代理可以代理多个类,只要实现同一个接口即可,代理的是接口!

8.2.5、缺点

比较抽象,难以理解。

8.2.6、深入理解

修改静态代理中 增删改查添加日志功能

UserService.java 不变

UserServiceImpl.java 不变

ProxyInvocationHandler.java 本方法具有通用性

public class ProxyInvocationHandler implements InvocationHandler {

//要代理的抽象角色

//接口类型:实现该接口的类都可以代理

private Object target;

public void setTarget(Object target) {

this.target = target;

}

//生成代理类,重点是第二个参数,获取要代理的抽象角色!之前都是一个角色,现在可以代理一类角色

public Object getProxy(){

return Proxy.newProxyInstance(

this.getClass().getClassLoader(), //类加载器

target.getClass().getInterfaces(), //要代理的接口列表

this //InvocationHandler 调用处理程序,就是当前类本身

);

}

// proxy : 代理类 method : 代理类的调用处理程序的方法对象.

// 处理代理实例上的方法调用并返回结果

@Override

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

log(method.getName());

//核心:本质利用反射实现!

Object res = method.invoke(target,args);

return res;

}

//代理的增强方法

private void log(String arg){

System.out.println(“[debug] 执行了”+arg+“方法”);

}

}

测试

public static void main(String[] args) {

//真实对象

UserService userService = new UserServiceImpl();

//代理对象的调用处理程序

ProxyInvocationHandler pih = new ProxyInvocationHandler();

pih.setTarget(userService); //设置要代理的对象

UserService proxy = (UserService)pih.getProxy(); //动态生成代理类!

proxy.delete();

}

9、 AOP

======

9.1、AOP概念


AOP(Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

9.2、AOP在Spring中的作用


  • 提供声明式事务

  • 允许用户自定义切面。增加日志 , 安全 , 缓存等等 …

Aop的重要性 : 很重要 . 一定要理解其中的思路 , 主要是思想的理解这一块 .

Spring的Aop就是将公共的业务 (日志 , 安全等) 和领域业务结合起来 , 当执行领域业务时 , 将会把公共业务加进来 . 实现公共业务的重复利用 . 领域业务更纯粹 , 程序猿专注领域业务 , 其本质还是动态代理 .

9.3、名词解释


  • 横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志 , 安全 , 缓存 , 事务等等 …

  • 切面(ASPECT):横切关注点 被模块化 的特殊对象。即,它是一个提供增强功能的类。

  • 通知(Advice):切面必须要完成的工作。即,它是类中的一个方法,即增强方法。

  • 目标(Target):被通知对象。

  • 代理(Proxy):向目标对象应用通知之后创建的对象。

  • 切入点(PointCut):切面通知 执行的 “地点”的定义。

  • 连接点(JointPoint):与切入点匹配的执行点。

9.4、Spring中AOP的实现方式


9.4.1、前提:导入依赖包

在MAVEN的Pom.xml中导入AOP依赖包

基础包:里面包含aop包

org.springframework

spring-webmvc

5.3.7

新增包:面向切面的

org.aspectj

aspectjweaver

1.9.6

9.4.2、通过 Spring API 实现

业务接口:UserService.java

public interface UserService {

public void add();

public void delete();

public void update();

public void select();

}

实现类:UserServiceImpl.java

public class UserServiceImpl implements UserService{

@Override

public void add() {

System.out.println(“添加记录”);

}

@Override

public void delete() {

System.out.println(“删除记录”);

}

@Override

public void update() {

System.out.println(“更新记录”);

}

@Override

public void select() {

System.out.println(“查询记录”);

}

}

前置日志增强类:Log.java

public class Log implements MethodBeforeAdvice {

@Override

//method : 要执行的目标对象的方法

//objects : 被调用的方法的参数

//Object : 目标对象

public void before(Method method, Object[] objects, Object o) throws Throwable {

System.out.println(o.getClass().getName()+" 的 “+ method.getName()+” 方法被执行了");

}

}

后置日志增强类:AfterLog.java

public class AfterLog implements AfterReturningAdvice {

@Override

//returnValue 返回值

//method被调用的方法

//args 被调用的方法的对象的参数

//target 被调用的目标对象

public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {

System.out.println(“执行了 “+target.getClass().getName()+” 的 “+method.getName()+” 的方法。返回值为:”+returnValue);

}

}

配置beans.xml

在头文件中添加aop命名空间支持。添加方法见 7.4.1

<?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: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/aop

http://www.springframework.org/schema/aop/spring-aop.xsd">

aop:config

<aop:pointcut id=“logPointCut”

expression=“execution(* com.ajun.pojo.UserServiceImpl.*(…))”/>

<aop:advisor advice-ref=“log” pointcut-ref=“logPointCut”/>

<aop:advisor advice-ref=“afterLog” pointcut-ref=“logPointCut”/>

</aop:config>

测试

@Test

public void test(){

ApplicationContext context = new ClassPathXmlApplicationContext(“beans.xml”);

UserService userService = context.getBean(“userService”, UserService.class);

userService.add();

}

9.4.3、自定义类实现

业务接口:UserService.java 不变

实现类:UserServiceImpl.java 不变

自定义切面类:MyAspect.java

public class MyAspect {

public void before(){

System.out.println(“=方法执行前=”);

}

public void after(){

System.out.println(“=方法执行后=”);

}

}

配置beans.xml

和第一种实现方法的配置不同:引入了 aop:aspect、aop:before、aop:after、method

aop:config

<aop:aspect ref=“myAspect”>

<aop:pointcut id=“myPointCut”

expression=“execution(* com.ajun.pojo.UserServiceImpl.*(…))”/>

<aop:before method=“before” pointcut-ref=“myPointCut”/>

<aop:after method=“after” pointcut-ref=“myPointCut”/>

</aop:aspect>

</aop:config>

测试方法不变

9.4.4、使用注解实现

业务接口:UserService.java 不变

实现类:UserServiceImpl.java 不变

自定义注解实现的切面类:AnnotationAspect.java

@Aspect

public class AnnotationAspect {

@Before(“execution(* com.ajun.pojo.UserServiceImpl.*(…))”)

public void before(){

System.out.println(“=方法执行前=”);

}

@After(value = “execution(* com.ajun.pojo.UserServiceImpl.*(…))”)

public void after(){

System.out.println(“=方法执行后=”);

}

@Around(“execution(* com.ajun.pojo.UserServiceImpl.*(…))”)

public void around(ProceedingJoinPoint pj) throws Throwable {

System.out.println(“=环绕前=”);

System.out.println(“签名:”+pj.getSignature());

//执行目标方法proceed

Object proceed = pj.proceed();

System.out.println(“=环绕后=”);

System.out.println(proceed);

}

}

配置beans.xml

aop:aspectj-autoproxy/

说明:

通过aop命名空间的<aop:aspectj-autoproxy />声明,自动为spring容器中那些配置@AspectJ切面的bean创建代理,织入切面。

当然,spring 在内部依旧采用AnnotationAwareAspectJAutoProxyCreator进行自动代理的创建工作,但具体实现的细节已经被<aop:aspectj-autoproxy />隐藏起来了

<aop:aspectj-autoproxy />有一个proxy-target-class属性,默认为false,表示使用jdk动态代理织入增强,当配为<aop:aspectj-autoproxy poxy-target-class=“true”/>时,表示使用CGLib动态代理技术织入增强。

不过即使proxy-target-class设置为false,如果目标类没有声明接口,则spring将自动使用CGLib动态代理。

测试方法不变

10、整合MyBatis

============

10.1、不整合时的写法


步骤:

1、导入相关jar包

  • junit测试包

junit

junit

4.13.2

test

  • spring框架包

org.springframework

spring-webmvc

5.3.7

  • spring jdbc包

org.springframework

spring-jdbc

5.3.7

  • mysql驱动包

mysql

mysql-connector-java

8.0.25

  • mybatis包

org.mybatis

mybatis

3.5.7

  • lombok包

org.projectlombok

lombok

1.18.20

provided

2、配置Maven静态资源过滤问题!

src/main/java

**/*.properties

**/*.xml

false

使用Maven构建项目的时候,会默认过滤掉静态资源,所以,需要手动来配置

静态资源 : 包含HTMl,图片,CSS,JS,xml等不需要与数据库交互的一类文件

动态资源 : 需要与数据库交互,可以根据需要显示不同的数据,不需要修改页面

如果把配置文件直接放在resources目录下,就不用过滤

3、代码实现

实体类:User.java

@Data

public class User {

private int id;

private String name;

private String pw;

}

Mapper接口及配置

//接口

public interface UserMapper {

public List getAll();

}

<?xml version="1.0" encoding="UTF-8" ?>

select * from user

4、mybatis配置文件

<?xml version="1.0" encoding="UTF-8" ?>

5、测试

@Test

public void test() throws IOException {

String resource = “mybatis-config.xml”;

InputStream inputStream = Resources.getResourceAsStream(resource);

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

SqlSession sqlSession = sqlSessionFactory.openSession(true);

UserMapper mapper = sqlSession.getMapper(UserMapper.class);

List userList = mapper.getAll();

for (User user: userList){

System.out.println(user);

}

sqlSession.close();

}

6、运行结果

7、注意事项

com.mysql.jdbc.Driver 和 com.mysql.cj.jdbc.Driver 如何选择

mysql-connector-java 6 以下用 com.mysql.jdbc.Driver

mysql-connector-java 6及以上用:com.mysql.cj.jdbc.Driver

10.2、MyBatis-Spring介绍


官方网址:mybatis-spring –

什么是 MyBatis-Spring?

MyBatis-Spring 会帮助你将 MyBatis 代码无缝地整合到 Spring 中。它将允许 MyBatis 参与到 Spring 的事务管理之中,创建映射器 mapper 和 SqlSession 并注入到 bean 中,以及将 Mybatis 的异常转换为 Spring 的 DataAccessException。 最终,可以做到应用代码不依赖于 MyBatis,Spring 或 MyBatis-Spring。

要和 Spring 一起使用 MyBatis,需要在 Spring 应用上下文中定义至少两样东西:

一个 SqlSessionFactory和至少一个数据映射器类。

在 MyBatis-Spring 中,可使用 SqlSessionFactoryBean来创建 SqlSessionFactory。 要配置这个工厂 bean,只需要把下面代码放在 Spring 的 XML 配置文件中:

需要注意的是:所指定的映射器类必须是一个接口,而不是具体的实现类。可以通过注解来指定 SQL 语句,也可以使用 MyBatis 映射器的 XML 配置文件。

在 MyBatis 中,你可以使用 SqlSessionFactory 来创建 SqlSession。 一旦你获得一个 session 之后,你可以使用它来执行映射了的语句,提交或回滚连接,最后,当不再需要它的时候,你可以关闭 session。 使用 MyBatis-Spring 之后,你不再需要直接使用 SqlSessionFactory 了,因为你的 bean 可以被注入一个线程安全的 SqlSession,它能基于 Spring 的事务配置来自动提交、回滚、关闭 session。

SqlSessionTemplate

SqlSessionTemplate 是 MyBatis-Spring 的核心。作为 SqlSession 的一个实现,这意味着可以使用它无缝代替你代码中已经在使用的 SqlSessionSqlSessionTemplate 是线程安全的,可以被多个 DAO 或映射器所共享使用。

当调用 SQL 方法时(包括由 getMapper() 方法返回的映射器中的方法),SqlSessionTemplate 将会保证使用的 SqlSession 与当前 Spring 的事务相关。 此外,它管理 session 的生命周期,包含必要的关闭、提交或回滚操作。另外,它也负责将 MyBatis 的异常翻译成 Spring 中的 DataAccessExceptions

由于模板可以参与到 Spring 的事务管理中,并且由于其是线程安全的,可以供多个映射器类使用,你应该总是SqlSessionTemplate 来替换 MyBatis 默认的 DefaultSqlSession 实现。在同一应用程序中的不同类之间混杂使用可能会引起数据一致性的问题。

可以使用 SqlSessionFactory 作为构造方法的参数来创建 SqlSessionTemplate 对象。

SqlSessionDaoSupport

SqlSessionDaoSupport 是一个抽象的支持类,用来为你提供 SqlSession。调用 getSqlSession() 方法你会得到一个 SqlSessionTemplate,之后可以用于执行 SQL 方法,就像下面这样:

public class UserDaoImpl extends SqlSessionDaoSupport implements UserDao {

public User getUser(String userId) {

return getSqlSession().selectOne(“org.mybatis.spring.sample.mapper.UserMapper.getUser”, userId);

}

}

在这个类里面,通常更倾向于使用 MapperFactoryBean,因为它不需要额外的代码。但是,如果你需要在 DAO 中做其它非 MyBatis 的工作或需要一个非抽象的实现类,那么这个类就很有用了。

SqlSessionDaoSupport 需要通过属性设置一个 sqlSessionFactorySqlSessionTemplate。如果两个属性都被设置了,那么 SqlSessionFactory 将被忽略。

假设类 UserMapperImplSqlSessionDaoSupport 的子类,可以编写如下的 Spring 配置来执行设置:

10.3、整合一 SqlSessionTemplate


1、导入相关jar包

除了10.1中的jar包外,还要导入:

  • mybatis和spring整合包

org.mybatis

mybatis-spring

2.0.6

2、配置Maven静态资源过滤问题!

同10.1中一样

3、代码实现

Dao实现类:UserMapperImpl.java

public class UserMapperImpl implements UserMapper{

//引入SqlSessionTemplate

//sqlSession不需要自已创建了

private SqlSessionTemplate sqlSessionTemplate;

public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {

this.sqlSessionTemplate = sqlSessionTemplate;

}

@Override

public List getAll() {

UserMapper mapper = sqlSessionTemplate.getMapper(UserMapper.class);

return mapper.getAll();

}

}

4、配置beans.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">

<property name=“url”

value=“jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf8”/>

此时mybatis-config.xml中的配置内容:数据源、实体类、dao,都被整合到了beans.xml中,所以mybatis-config.xml也就可以删除了

5、测试

@Test

public void test() throws IOException {

ApplicationContext context = new ClassPathXmlApplicationContext(“beans.xml”);

UserMapper userMapper = context.getBean(“userMapper”, UserMapper.class);

List users = userMapper.getAll();

for (User user: users){

System.out.println(user);

}

}

6、运行结果

7、注意事项

和10.1 中的注意事项一样

10.4、整合二 SqlSessionDaoSupport


在10.3的基础上做如下修改:

1、代码修改

UserMapperImpl.java

public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper {

@Override

public List getAll() {

//UserMapper mapper = getSqlSession().getMapper(UserMapper.class);

//mapper.getAll();

return getSqlSession().getMapper(UserMapper.class).getAll();

}

}

继承SqlSessionDaoSupport抽象类

不需要定义SqlSessionTemplate

通过父类的getSqlSession()直接获取sqlSession

2、beans.xml修改

不需要注册SqlSessionTemplate,直接把SqlSessionFactory注入到Dao实现类中就可以

3、测试

测试方法和 10.3 中一致

4、运行结果

10.5、整合三 注解 (Spring Boot时再学)


11、声明式事务

========

1、事务概述


  • 事务在项目开发过程非常重要,涉及到数据的一致性的问题,不容马虎!

  • 事务管理是企业级应用程序开发中必备技术,用来确保数据的完整性和一致性。

  • 事务就是把一系列的动作当成一个独立的工作单元,这些动作要么全部完成,要么全部失败

事务四个属性ACID
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

总结

谈到面试,其实说白了就是刷题刷题刷题,天天作死的刷。。。。。

为了准备这个“金三银四”的春招,狂刷一个月的题,狂补超多的漏洞知识,像这次美团面试问的算法、数据库、Redis、设计模式等这些题目都是我刷到过的

并且我也将自己刷的题全部整理成了PDF或者Word文档(含详细答案解析)

我的美团offer凉凉了?开发工程师(Java岗)三面结束等通知...

66个Java面试知识点

架构专题(MySQL,Java,Redis,线程,并发,设计模式,Nginx,Linux,框架,微服务等)+大厂面试题详解(百度,阿里,腾讯,华为,迅雷,网易,中兴,北京中软等)

我的美团offer凉凉了?开发工程师(Java岗)三面结束等通知...

算法刷题(PDF)

我的美团offer凉凉了?开发工程师(Java岗)三面结束等通知...

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
因为SqlSessionTemplate没有set方法

–>

此时mybatis-config.xml中的配置内容:数据源、实体类、dao,都被整合到了beans.xml中,所以mybatis-config.xml也就可以删除了

5、测试

@Test

public void test() throws IOException {

ApplicationContext context = new ClassPathXmlApplicationContext(“beans.xml”);

UserMapper userMapper = context.getBean(“userMapper”, UserMapper.class);

List users = userMapper.getAll();

for (User user: users){

System.out.println(user);

}

}

6、运行结果

7、注意事项

和10.1 中的注意事项一样

10.4、整合二 SqlSessionDaoSupport


在10.3的基础上做如下修改:

1、代码修改

UserMapperImpl.java

public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper {

@Override

public List getAll() {

//UserMapper mapper = getSqlSession().getMapper(UserMapper.class);

//mapper.getAll();

return getSqlSession().getMapper(UserMapper.class).getAll();

}

}

继承SqlSessionDaoSupport抽象类

不需要定义SqlSessionTemplate

通过父类的getSqlSession()直接获取sqlSession

2、beans.xml修改

不需要注册SqlSessionTemplate,直接把SqlSessionFactory注入到Dao实现类中就可以

3、测试

测试方法和 10.3 中一致

4、运行结果

10.5、整合三 注解 (Spring Boot时再学)


11、声明式事务

========

1、事务概述


  • 事务在项目开发过程非常重要,涉及到数据的一致性的问题,不容马虎!

  • 事务管理是企业级应用程序开发中必备技术,用来确保数据的完整性和一致性。

  • 事务就是把一系列的动作当成一个独立的工作单元,这些动作要么全部完成,要么全部失败

事务四个属性ACID
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。[外链图片转存中…(img-h8u2n8U3-1713541144788)]

[外链图片转存中…(img-oN8TPM7z-1713541144791)]

[外链图片转存中…(img-RSTalbRm-1713541144793)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

总结

谈到面试,其实说白了就是刷题刷题刷题,天天作死的刷。。。。。

为了准备这个“金三银四”的春招,狂刷一个月的题,狂补超多的漏洞知识,像这次美团面试问的算法、数据库、Redis、设计模式等这些题目都是我刷到过的

并且我也将自己刷的题全部整理成了PDF或者Word文档(含详细答案解析)

[外链图片转存中…(img-EqiVBeRy-1713541144794)]

66个Java面试知识点

架构专题(MySQL,Java,Redis,线程,并发,设计模式,Nginx,Linux,框架,微服务等)+大厂面试题详解(百度,阿里,腾讯,华为,迅雷,网易,中兴,北京中软等)

[外链图片转存中…(img-5i7kdoAD-1713541144796)]

算法刷题(PDF)

[外链图片转存中…(img-UP7ddh95-1713541144798)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值