spring 学习笔记

复制代码

复制代码

复制代码

  1. 测试

@Test

public void testT(){

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

UserT user = (UserT) context.getBean(“userT”);

user.show();

}

复制代码

结论:在配置文件加载的时候。其中管理的对象都已经初始化了!

5、Spring配置

==========

5.1. 别名


alias 设置别名 , 为bean设置别名 , 可以设置多个别名

复制代码

5.2. Bean的配置


复制代码

5.3. import


团队的合作通过import来实现.

复制代码

6、依赖注入(DI)

==========

  • 依赖注入(Dependency Injection,DI)。

  • 依赖 : 指Bean对象的创建依赖于容器 . Bean对象的依赖资源 .

  • 注入 : 指Bean对象所依赖的资源 , 由容器来设置和装配 .

6.1 构造器注入


参考 4、IOC创建对象的方式

6.2 set注入 (重点)


要求被注入的属性 , 必须有set方法 , set方法的方法名由set + 属性首字母大写 , 如果属性是boolean类型 , 没有set方法 , 是 is .

测试pojo类 : Address.java

public class Address {

private String address;

public String getAddress() {

return address;

}

public void setAddress(String address) {

this.address = address;

}

}

复制代码

Student.java

package com.angus.pojo;

import java.util.List;

import java.util.Map;

import java.util.Properties;

import java.util.Set;

public class Student {

private String name;

private Address address;

private String[] books;

private List hobbys;

private Map<String,String> card;

private Set games;

private String wife;

private Properties info;

public void setName(String name) {

this.name = name;

}

public void setAddress(Address address) {

this.address = address;

}

public void setBooks(String[] books) {

this.books = books;

}

public void setHobbys(List hobbys) {

this.hobbys = hobbys;

}

public void setCard(Map<String, String> card) {

this.card = card;

}

public void setGames(Set games) {

this.games = games;

}

public void setWife(String wife) {

this.wife = wife;

}

public void setInfo(Properties info) {

this.info = info;

}

public void show(){

System.out.println(“name=”+ name

  • “,address=”+ address.getAddress()

  • “,books=”

);

for (String book:books){

System.out.print(“<<”+book+“>>\t”);

}

System.out.println(“\n爱好:”+hobbys);

System.out.println(“card:”+card);

System.out.println(“games:”+games);

System.out.println(“wife:”+wife);

System.out.println(“info:”+info);

}

}

复制代码

1、常量注入

复制代码

测试:

public class MyTest {

public static void main(String[] args) {

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

Student student = (Student) context.getBean(“student”);

System.out.println(student.getName());

}

}

复制代码

2、Bean注入

注意点:这里的值是一个引用,ref

复制代码

3、数组注入

西游记

红楼梦

水浒传

复制代码

4、List注入

听歌

看电影

爬山

复制代码

5、Map注入

复制代码

6、set注入

LOL

BOB

COC

复制代码

7、Null注入

复制代码

8、Properties注入

20190604

angus

复制代码

测试结果

image.png

6.3 拓展注入实现


User.java : 【注意:这里没有有参构造器!】

public class User {

private String name;

private int age;

public void setName(String name) {

this.name = name;

}

public void setAge(int age) {

this.age = age;

}

@Override

public String toString() {

return “User{” +

“name='” + name + ‘’’ +

“, age=” + age +

‘}’;

}

}

复制代码

1、P命名空间注入 : 需要在头文件中假如约束文件

导入约束 : xmlns:p=“http://www.springframework.org/schema/p”

复制代码

2、c 命名空间注入 : 需要在头文件中加入约束文件

导入约束 : xmlns:c=“http://www.springframework.org/schema/c”

复制代码

发现问题:爆红了,刚才我们没有写有参构造! 解决:把有参构造器加上,这里也能知道,c 就是所谓的构造器注入!

测试代码:

@Test

public void test02(){

ApplicationContext context = new

ClassPathXmlApplicationContext(“applicationContext.xml”);

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

System.out.println(user);

}

复制代码

6.4 Bean的作用域


在Spring中,那些组成应用程序的主体及由Spring IoC容器所管理的对象,被称之为bean。简单地讲, bean就是由IoC容器初始化、装配及管理的对象 .

image.png

几种作用域中,request、session作用域仅在基于web的应用中使用(不必关心你所采用的是什么web 应用框架),只能用在基于web的Spring ApplicationContext环境。

6.4.1 Singleton

当一个bean的作用域为Singleton,那么Spring IoC容器中只会存在一个共享的bean实例,并且所有对 bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。Singleton是单例类型,就是 在创建起容器时就同时自动创建了一个bean的对象,不管你是否使用,他都存在了,每次获取到的对象 都是同一个对象。注意,Singleton作用域是Spring中的缺省作用域。要在XML中将bean定义成 singleton,可以这样配置:

复制代码

测试:

@Test

public void test03(){

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

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

User user2 = (User) context.getBean(“user”);

System.out.println(user==user2);

}

复制代码

6.4.2 Prototype

当一个bean的作用域为Prototype,表示一个bean定义对应多个对象实例。Prototype作用域的bean会 导致在每次对该bean请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法) 时都会创建一个新的bean实例。Prototype是原型类型,它在我们创建容器的时候并没有实例化,而是 当我们获取bean的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象。根据经 验,对有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用singleton作用域。在 XML中将bean定义成prototype,可以这样配置:

或者

复制代码

6.4.3 Request

当一个bean的作用域为Request,表示在一次HTTP请求中,一个bean定义对应一个实例;即每个HTTP 请求都会有各自的bean实例,它们依据某个bean定义创建而成。该作用域仅在基于web的Spring ApplicationContext情形下有效。考虑下面bean定义:

<bean id=“loginAction” class=cn.csdn.LoginAction" scope=“request”/>

复制代码

针对每次HTTP请求,Spring容器会根据loginAction bean的定义创建一个全新的LoginAction bean实 例,且该loginAction bean实例仅在当前HTTP request内有效,因此可以根据需要放心的更改所建实例 的内部状态,而其他请求中根据loginAction bean定义创建的实例,将不会看到这些特定于某个请求的 状态变化。当处理请求结束,request作用域的bean实例将被销毁。

6.4.4 Session

当一个bean的作用域为Session,表示在一个HTTP Session中,一个bean定义对应一个实例。该作用域 仅在基于web的Spring ApplicationContext情形下有效。考虑下面bean定义:

复制代码

针对某个HTTP Session,Spring容器会根据userPreferences bean定义创建一个全新的 userPreferences bean实例,且该userPreferences bean仅在当前HTTP Session内有效。与request作 用域一样,可以根据需要放心的更改所创建实例的内部状态,而别的HTTP Session中根据 userPreferences创建的实例,将不会看到这些特定于某个HTTP Session的状态变化。当HTTP Session 最终被废弃的时候,在该HTTP Session作用域内的bean也会被废弃掉。

7、Bean的自动装配

===========

  • 自动装配是使用spring满足bean依赖的一种方法

  • spring会在应用上下文中为某个bean寻找其依赖的bean。

Spring中bean有三种装配机制,分别是:

  1. 在xml中显式配置;

  2. 在java中显式配置;

  3. 隐式的bean发现机制和自动装配。

这里我们主要讲第三种:自动化的装配bean。

Spring的自动装配需要从两个角度来实现,或者说是两个操作:

  1. 组件扫描(component scanning):spring会自动发现应用上下文中所创建的bean;

  2. 自动装配(autowiring):spring自动满足bean之间的依赖,也就是我们说的IoC/DI;

组件扫描和自动装配组合发挥巨大威力,使的显示的配置降低到最少。

推荐 不使用自动装配xml配置 , 而是使用注解 .

7.1、测试环境搭建


  1. 新建一个项目

  2. 新建两个实体类,Cat Dog 都有一个叫的方法

public class Cat {

public void shout() {

System.out.println(“miao~”);

}

}

复制代码

public class Dog {

public void shout() {

System.out.println(“wang~”);

}

}

复制代码

  1. 新建一个用户类 User

public class User {

private Cat cat;

private Dog dog;

private String str;

}

复制代码

  1. 编写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”

xsi:schemaLocation="http://www.springframework.org/schema/beans

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

复制代码

  1. 测试

public class MyTest {

@Test

public void testMethodAutowire() {

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

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

user.getCat().shout();

user.getDog().shout();

}

}

复制代码

7.2、byName


autowire byName (按名称自动装配) 由于在手动配置xml过程中,常常发生字母缺漏和大小写等错误,而无法对其进行检查,使得开发效率 降低。 采用自动装配将避免这些错误,并且使配置简单化。

测试:

  1. 修改bean配置,增加一个属性 autowire=“byName”

复制代码

  1. 再次测试,结果依旧成功输出!

  2. 我们将 cat 的bean id修改为 catXXX

  3. 再次测试, 执行时报空指针java.lang.NullPointerException。因为按byName规则找不对应set方法,真正的setCat就没执行,对象就没有初始化,所以调用时就会报空指针错误。

小结: 当一个bean节点带有 autowire byName的属性时。

  1. 将查找其类中所有的set方法名,例如setCat,获得将set去掉并且首字母小写的字符串,即cat。

  2. 去spring容器中寻找是否有此字符串名称id的对象。

  3. 如果有,就取出注入;如果没有,就报空指针异常。

7.3、byType


autowire byType (按类型自动装配) 使用autowire byType首先需要保证:同一类型的对象,在spring容器中唯一。如果不唯一,会报不唯一 的异常。

NoUniqueBeanDefinitionException

复制代码

测试:

  1. 将user的bean配置修改一下 : autowire=“byType”

  2. 测试,正常输出

  3. 在注册一个cat 的bean对象!

复制代码

  1. 测试,报错:NoUniqueBeanDefinitionException

  2. 删掉cat2,将cat的bean名称改掉!测试!因为是按类型装配,所以并不会报异常,也不影响最后

的结果。甚至将id属性去掉,也不影响结果。

这就是按照类型自动装配!

7.4、使用注解


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

准备工作: 利用注解的方式注入属性。

  1. 在spring配置文件中引入context文件头

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

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

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

复制代码

添加之后的结果

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

xsi:schemaLocation="http://www.springframework.org/schema/beans

https://www.springframework.org/schema/beans/spring-beans.xsd

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

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

context:annotation-config/

复制代码

  1. 开启属性注解支持!

context:annotation-config/

复制代码

7.4.1、@Autowired

  • @Autowired 是按类型自动转配的,不支持id匹配。

  • 需要导入 spring-aop的包!

测试:

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

public class User {

@Autowired

private Cat cat;

@Autowired

private Dog dog;

private String str;

public Cat getCat() {

return cat;

}

public Dog getDog() {

return dog;

}

public String getStr() {

return str;

}

}

复制代码

  1. 此时配置文件内容

context:annotation-config/

复制代码

  1. 测试,成功输出结果!

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

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

@Autowired(required = false)

private Cat cat;

复制代码

7.4.2、@Qualifier

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

  • @Qualifier不能单独使用。

测试实验步骤:

  1. 配置文件修改内容,保证类型存在对象。且名字不为类的默认名字!

复制代码

  1. 没有加Qualifier测试,直接报错

  2. 在属性上添加Qualifier注解

@Autowired

@Qualifier(value = “cat2”)

private Cat cat;

@Autowired

@Qualifier(value = “dog2”)

private Dog dog;

复制代码

  1. 测试,成功输出!

7.4.3、@Resource

  • @Resource如有指定的name属性,先按该属性进行byName方式查找装配;

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

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

  • 都不成功,则报异常。

实体类:

public class User {

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

@Resource(name = “cat2”)

private Cat cat;

@Resource

private Dog dog;

private String str;

}

复制代码

beans.xml

复制代码

测试:结果OK 配置文件2:beans.xml , 删掉cat2

复制代码

实体类上只保留注解

@Resource

private Cat cat;

@Resource

private Dog dog;

复制代码

结果:OK

结论:先进行byName查找,失败;再进行byType查找,成功。

7.5、小结


@Autowired与@Resource异同:

  1. @Autowired与@Resource都可以用来装配bean。都可以写在字段上,或写在setter方法上。

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

  3. @Resource(属于J2EE复返),默认按照名称进行装配,名称可以通过name属性进行指定。如果没有指定name属性,当注解写在字段上时,默认取字段名进行按照名称查找,如果注解写在setter方法上默认取属性名进行装配。 当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。它们的作用相同都是用注解方式注入对象,但执行顺序不同。@Autowired先byType,@Resource先byName。

8、使用注解开发

========

8.1、说明


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

image.png

在配置文件当中,还得要引入一个context约束

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

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

复制代码

8.2、Bean的实现


我们之前都是使用 bean 的标签进行bean注入,但是实际开发中,我们一般都会使用注解!

  1. 配置扫描哪些包下的注解

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

复制代码

  1. 在指定包下编写类,增加注解

@Component(“user”)

// 相当于配置文件中

public class User {

public String name = “angus”;

}

复制代码

  1. 测试

@Test

public void test(){

ApplicationContext applicationContext =

new ClassPathXmlApplicationContext(“beans.xml”);

User user = (User) applicationContext.getBean(“user”);

System.out.println(user.name);

}

复制代码

8.3、属性注入


使用注解注入属性

  1. 可以不用提供set方法,直接在直接名上添加@value(“值”)

@Component(“user”)

// 相当于配置文件中

public class User {

@Value(“angus”)

// 相当于配置文件中

public String name;

}

复制代码

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

@Component(“user”)

public class User {

public String name;

@Value(“angus”)

public void setName(String name) {

this.name = name;

}

}

复制代码

8.4、衍生注解


我们这些注解,就是替代了在配置文件当中配置步骤而已!更加的方便快捷!

@Component三个衍生注解

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

  • @Controller:web层

  • @Service:service层

  • @Repository:dao层

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

8.5、自动装配注解


在Bean的自动装配已经讲过了,可以回顾!

8.6、作用域


@scope

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

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

@Controller(“user”)

@Scope(“prototype”)

public class User {

@Value(“angus”)

public String name;

}

复制代码

8.7、小结


XML与注解比较

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

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

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

  • xml管理Bean

  • 注解完成属性注入

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

作用:

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

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

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

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

8.8、基于Java类进行配置


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

测试:

  1. 编写一个实体类,Dog

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

public class Dog {

public String name = “dog”;

}

复制代码

  1. 新建一个config配置包,编写一个MyConfig配置类

@Configuration  //代表这是一个配置类

public class MyConfig {

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

public Dog dog(){

return new Dog();

}

}

复制代码

  1. 测试

@Test

public void test2(){

ApplicationContext applicationContext =

new AnnotationConfigApplicationContext(MyConfig.class);

Dog dog = (Dog) applicationContext.getBean(“dog”);

System.out.println(dog.name);

}

复制代码

  1. 成功输出结果!

导入其他配置如何做呢?

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

@Configuration  //代表这是一个配置类

public class MyConfig2 {

}

复制代码

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

@Configuration

@Import(MyConfig2.class)  //导入合并其他配置类,类似于配置文件中的 inculde 标签

public class MyConfig {

@Bean

public Dog dog(){

return new Dog();

}

}

复制代码

关于这种Java类的配置方式,我们在之后的SpringBoot 和 SpringCloud中还会大量看到,我们需要知道 这些注解的作用即可!

9、代理模式

======

为什么要学习代理模式,因为AOP的底层机制就是动态代理!

image.png

9.1、静态代理


静态代理角色分析

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

  • 真实角色 : 被代理的角色

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

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

代码实现 Rent.java 即抽象角色

//抽象角色:租房

public interface Rent {

public void rent();

}

复制代码

Host.java 即真实角色

//真实角色: 房东,房东要出租房子

public class Host implements Rent{

public void rent() {

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

}

}

复制代码

Proxy.java 即代理角色

//代理角色:中介

public class Proxy implements Rent {

private Host host;

public Proxy() { }

public Proxy(Host host) {

this.host = host;

}

//租房

public void rent(){

seeHouse();

host.rent();

fare();

}

//看房

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();

//中介帮助房东

Proxy proxy = new Proxy(host);

//你去找中介!

proxy.rent();

}

}

复制代码

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

9.2、静态代理的好处


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

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

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

缺点 :

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

我们想要静态代理的好处,又不想要静态代理的缺点,所以 , 就有了动态代理 !

9.3、静态代理再理解


同学们练习完毕后,我们再来举一个例子,巩固大家的学习! 练习步骤:

  1. 创建一个抽象角色,比如咋们平时做的用户业务,抽象起来就是增删改查!

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

public interface UserService {

void add();

void delete();

void update();

void query();

}

复制代码

  1. 我们需要一个真实对象来完成这些增删改查操作

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

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(“查询了一个用户”);

}

}

复制代码

  1. 需求来了,现在我们需要增加一个日志功能,怎么实现!
  • 思路1 :在实现类上增加代码 【麻烦!】

  • 思路2:使用代理来做,能够不改变原来的业务情况下,实现此功能就是最好的了!

  1. 设置一个代理类来处理日志! 代理角色

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

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+“方法”);

}

}

复制代码

  1. 测试访问类:

public class Client {

public static void main(String[] args) {

//真实业务

UserServiceImpl userService = new UserServiceImpl();

//代理类

UserServiceProxy proxy = new UserServiceProxy();

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

proxy.setUserService(userService);

proxy.add();

}

}

复制代码

OK,到了现在代理模式大家应该都没有什么问题了,重点大家需要理解其中的思想; 我们在不改变原来的代码的情况下,实现了对原有功能的增强,这是AOP中最核心的思想 【聊聊AOP:纵向开发,横向开发】

image.png

9.4、动态代理


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

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

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

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

  • 基于类的动态代理–cglib

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

  • 我们这里使用JDK的原生代码来实现,其余的道理都是一样的!

JDK的动态代理需要了解两个类 核心 : InvocationHandler 和 Proxy , 打开JDK帮助文档看看 【InvocationHandler:调用处理程序】

image.png

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

//参数

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

//method -所述方法对应于调用代理实例上的接口方法的实例。 方法对象的声明类将是该方法声明的接

// 口,它可以是代理类继承该方法的代理接口的超级接口。

//args -包含的方法调用传递代理实例的参数值的对象的阵列,或null如果接口方法没有参数。 原始

// 类型的参数包含在适当的原始包装器类的实例中,例如java.lang.Integer或java.lang.Boolean

复制代码

【Proxy : 代理】

image.png

image.png

image.png

//生成代理类

public Object getProxy(){

return Proxy.newProxyInstance(this.getClass().getClassLoader(),

rent.getClass().getInterfaces(),this);

}

复制代码

代码实现 抽象角色和真实角色和之前的一样! Rent.java 即抽象角色

//抽象角色:租房

public interface Rent {

public void rent();

}

复制代码

Host.java 即真实角色

//真实角色: 房东,房东要出租房子

public class Host implements Rent{

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);

}

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

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

@Override

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

Throwable {

seeHouse();

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

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

fare();

return result;

}

//看房

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();

}

}

复制代码

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

9.5、深化理解


我们来使用动态代理实现代理我们后面写的UserService! 我们也可以编写一个通用的动态代理实现的类!所有的代理对象设置为Object即可!

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);

}

// proxy : 代理类

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

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

Throwable {

log(method.getName());

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

return result;

}

public void log(String methodName){

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

}

}

复制代码

测试!

public class Test {

public static void main(String[] args) {

//真实对象

UserServiceImpl userService = new UserServiceImpl();

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

ProxyInvocationHandler pih = new ProxyInvocationHandler();

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

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

proxy.delete();

}

}

复制代码

【测试,增删改查,查看结果】

9.6、动态代理的好处


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

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

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

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

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

  • 一个动态代理可以代理多个类,代理的是接口!

10、AOP

======

10.1 什么是AOP


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

image.png

10.2 Aop在Spring中的作用


提供声明式事务;允许用户自定义切面

  • 横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要

  • 关注的部分,就是横切关注点。如日志 , 安全 , 缓存 , 事务等等 …

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

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

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

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

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

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

image.png

SpringAOP中,通过Advice定义横切逻辑,Spring中支持5种类型的Advice:

image.png

即 Aop 在 不改变原有代码的情况下, 去增加新的功能。

10.3 使用Spring实现Aop


【重点】使用AOP织入,需要导入一个依赖包!

org.aspectj

aspectjweaver

1.9.4

复制代码

第一种方式

通过 Spring API 实现 首先编写我们的业务接口和实现类

public interface UserService {

public void add();

public void delete();

public void update();

public void search();

}

复制代码

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 search() {

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

}

}

复制代码

然后去写我们的增强类 , 我们编写两个 , 一个前置增强 一个后置增强

public class Log implements MethodBeforeAdvice {

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

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

//Object : 目标对象

@Override

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

Throwable {

System.out.println( o.getClass().getName() + “的” + method.getName()

  • “方法被执行了”);

}

}

复制代码

public class AfterLog implements AfterReturningAdvice {

//returnValue 返回值

//method被调用的方法

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

//target 被调用的目标对象

@Override

public void afterReturning(Object returnValue, Method method, Object[]

args, Object target) throws Throwable {

System.out.println(“执行了” + target.getClass().getName()

+“的”+method.getName()+“方法,”

+“返回值:”+returnValue);

}

}

复制代码

最后去spring的文件中注册 , 并实现aop切入实现 , 注意导入约束.

<?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=“pointcut” expression="execution(*

com.kuang.service.UserServiceImpl.*(…))"/>

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

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

</aop:config>

复制代码

测试

public class MyTest {

@Test

public void test(){

ApplicationContext context = new

ClassPathXmlApplicationContext(“beans.xml”);

UserService userService = (UserService)

context.getBean(“userService”);

userService.search();

}

}

复制代码

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

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

第二种方式

自定义类来实现Aop

目标业务类不变依旧是userServiceImpl

第一步 : 写我们自己的一个切入类

public class DiyPointcut {

public void before(){

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

}

public void after(){

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

}

}

复制代码

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

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

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

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

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

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

img

写在最后

为了这次面试,也收集了很多的面试题!

以下是部分面试题截图

Java程序员秋招三面蚂蚁金服,我总结了所有面试题,也不过如此
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
e 返回值

//method被调用的方法

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

//target 被调用的目标对象

@Override

public void afterReturning(Object returnValue, Method method, Object[]

args, Object target) throws Throwable {

System.out.println(“执行了” + target.getClass().getName()

+“的”+method.getName()+“方法,”

+“返回值:”+returnValue);

}

}

复制代码

最后去spring的文件中注册 , 并实现aop切入实现 , 注意导入约束.

<?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=“pointcut” expression="execution(*

com.kuang.service.UserServiceImpl.*(…))"/>

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

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

</aop:config>

复制代码

测试

public class MyTest {

@Test

public void test(){

ApplicationContext context = new

ClassPathXmlApplicationContext(“beans.xml”);

UserService userService = (UserService)

context.getBean(“userService”);

userService.search();

}

}

复制代码

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

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

第二种方式

自定义类来实现Aop

目标业务类不变依旧是userServiceImpl

第一步 : 写我们自己的一个切入类

public class DiyPointcut {

public void before(){

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

}

public void after(){

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

}

}

复制代码

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

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

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

[外链图片转存中…(img-NslWzyMg-1712675444168)]

[外链图片转存中…(img-W9zetYHV-1712675444168)]

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

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

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

img

写在最后

为了这次面试,也收集了很多的面试题!

以下是部分面试题截图

[外链图片转存中…(img-vV22nsQl-1712675444169)]
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 22
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值