星期二 2021年2月23日 spring 12-19

2023-10-25 14:40
文章标签 java spring 23 2021 19 星期二

本文主要是介绍星期二 2021年2月23日 spring 12-19,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在这里插入图片描述

在这里插入图片描述

7、Bean的自动装配

  • 自动装配是Spring满足bean依赖的一种方式
  • Spring会在上下文中自动寻找,并自动给bean装配属性

在Spring中有三种装配的方式

  1. 在xml中显示的配置
  2. 在java中显示的配置
  3. 隐式的自动装配bean 【重要】

7.1 测试

  • 新建一个maven项目,spring-05-Autowired 的项目。

  • src/main/java中,新建包com.kuang.pojo,在其中新建3份class文件:Dog,Cat,People。

// Cat
package com.kuang.pojo;public class Cat {public void shout() {System.out.println("miao~");}
}
// Dog
package com.kuang.pojo;public class Dog {public void shout() {System.out.println("wang~");}
}
// People
package com.kuang.pojo;public class People {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;}@Overridepublic String toString() {return "People{" +"cat=" + cat +", dog=" + dog +", name='" + name + '\'' +'}';}
}
  • resources中新建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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"></beans>

环境搭建:一个人有两个宠物

7.2 byName自定装配

1.不使用byName
  • beans.xml文件添加下面的内容:
    <bean id="cat" class="com.kuang.pojo.Cat"/><bean id="dog" class="com.kuang.pojo.Dog"/><bean id="people" class="com.kuang.pojo.People"><property name="name" value="狂神"/><property name="dog" ref="dog"/><property name="cat" ref="cat"/></bean>
    • 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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="cat" class="com.kuang.pojo.Cat"/><bean id="dog" class="com.kuang.pojo.Dog"/><bean id="people" class="com.kuang.pojo.People"><property name="name" value="狂神"/><property name="dog" ref="dog"/><property name="cat" ref="cat"/></bean>
</beans>

test.java中新建MyTest的class文件。

import com.kuang.pojo.People;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class MyTest {@Testpublic void test1() {ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");People people = context.getBean("people", People.class);people.getDog().shout();people.getCat().shout();}
}
  • pom.xml加上下面代码:
 <dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency></dependencies>
  • 结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P4jzvRnL-1614090199491)(C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20210223094312885.png)]

[13、注解实现自动装配]

2.使用autowire实现自动装配。byName

beans.xml文件修改内容:

    <bean id="people" class="com.kuang.pojo.People" autowire="byName"><property name="name" value="狂神"/></bean>加上了autowire="byName"
删除了<property name="dog" ref="dog"/>
删除了<property name="cat" ref="cat"/>

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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="cat" class="com.kuang.pojo.Cat"/><bean id="dog" class="com.kuang.pojo.Dog"/><bean id="people" class="com.kuang.pojo.People" autowire="byName"><property name="name" value="狂神"/></bean>
</beans>
  • 运行程序,结果和上次一样。

image-20210223094312885

byName : 会自动在容器上下文中查找,和自己对象set方法后面的值对应的bean_id

7.3 byTpye自动装配

byName : 会自动在容器上下文中查找,和自己对象set方法后面的值对应的bean_id
byType : 会自动在容器上下文中查找,和自己对象属性类型相同的bean

beans.xml文件修改内容:

    <bean id="people" class="com.kuang.pojo.People" autowire="byName"><property name="name" value="狂神"/></bean>修改autowire="byType"<bean id="people" class="com.kuang.pojo.People" autowire="byType"><property name="name" value="狂神"/></bean>

并将beans.xml文件修改内容:

<bean id="dog" class="com.kuang.pojo.Dog"/>
修改为:
<bean id="dog1111" class="com.kuang.pojo.Dog"/>

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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="cat" class="com.kuang.pojo.Cat"/><bean id="dog1111" class="com.kuang.pojo.Dog"/><bean id="people" class="com.kuang.pojo.People" autowire="byType"><property name="name" value="狂神"/></bean>
</beans>
  • 运行程序,结果和上次一样。

image-20210223094312885

小结:

  • byName的时候,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致
  • byType的时候,需要保证所有bean的class唯一,并且这个bean需要和自动注入的属性的类型一致

image-20210223095619632

7.4 使用注解实现自动装配

jdk1.5支持的注解,Spring2.5就支持注解了!

要使用注解须知:

1.导入约束

xmlns:context="http://www.springframework.org/schema/context"

2.配置注解的支持 context:annotation-config/

<context:annotation-config/>

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"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttps://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsdhttps://www.springframework.org/schema/aop/spring-aophttps://www.springframework.org/schema/aop/spring-aop.xsd"><context:annotation-config/><bean id="cat" class="com.kuang.pojo.Cat"/><bean id="dog" class="com.kuang.pojo.Dog"/><bean id="people" class="com.kuang.pojo.People"/></beans>

@Autowired

  • 在people中加上@Autowired

这里的程序没有运行成功啊。

原因是因为http和https,在这两处写错了。

直接在属性上使用即可,也可以在set方法上使用

使用Autowired我们可以不用编写set方法了,前提是你这个自动装配的属性在 IOC(Spring)容器中存在,且符合名字byName

科普:

@Nullable	字段标记了这个注解,说明这个字段可以为null;
1
public @interface Autowired {boolean required() default true;
}

测试代码:

public class People {//如果显示定义了Autowired的required属性为false,说明这个对象可以为Null,否则不允许为空@Autowired(required = false)private Cat cat;@Autowiredprivate Dog dog;private String name;
}

如果@Autowired自动装配的环境比较复杂,自动装配无法通过一个注解【@Autowired】完成的时候,我们可以使用==@Qualifier(value = “xxx”)==去配合@Autowire的使用,指定一个唯一的bean对象注入!

public class People {@Autowired@Qualifier(value = "cat2")private Cat cat;@Autowiredprivate Dog dog;private String name;
}

@Resource

public class People {@Resource( name = "cat3")private Cat cat;@Resourceprivate Dog dog;private String name;
}
12345678

小结:

@Resource和@Autowired的区别:

  • 都是用来自动转配的,都可以放在属性字段上
  • @Autowired 是通过byType的方式实现,而且必须要求这个对象存在!【常用】
  • @Resource 默认通过byName的方式实现,如果找不到名字,则通过byType实现!如果两个都找不到的情况下,就报错!【常用】
  • 执行顺序不同: @Autowired 通过byType的方式实现。@Resource默认通过byName的方式实现。

入!

public class People {@Autowired@Qualifier(value = "cat2")private Cat cat;@Autowiredprivate Dog dog;private String name;
}
123456789

@Resource

public class People {@Resource( name = "cat3")private Cat cat;@Resourceprivate Dog dog;private String name;
}
12345678

小结:

@Resource和@Autowired的区别:

  • 都是用来自动转配的,都可以放在属性字段上
  • @Autowired 是通过byType的方式实现,而且必须要求这个对象存在!【常用】
  • @Resource 默认通过byName的方式实现,如果找不到名字,则通过byType实现!如果两个都找不到的情况下,就报错!【常用】
  • 执行顺序不同: @Autowired 通过byType的方式实现。@Resource默认通过byName的方式实现。

8、使用注解开发

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

  • 自己的和狂神的一样啊。不知道为啥上面的不对。http和https这两点出错。

image-20210223111320949

  • 新建一个spring-06-anno的maven项目。

  • resources中新建 applicationContext.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"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsd"><context:annotation-config/></beans>
  • src/main/java中新建包com.kuang.pojo,在其中新建User.java的文件,并在applicationContext.xml增加内容:
    <!----><context:component-scan base-package="com.kuang.pojo"/><context:annotation-config/>
<?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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsd"><!----><context:component-scan base-package="com.kuang.pojo"/><context:annotation-config/></beans>
  • src/main/java中新建包com.kuang.controller,com.kuang.dao,com.kuang.service。
  • User.java添加内容:
package com.kuang.pojo;import org.springframework.stereotype.Component;@Component
public class User {public String name = "琴江";
}
  • test/java中新建MyTest.java文件。
import com.kuang.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class MyTest {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");User user = (User) context.getBean("user");System.out.println(user.name);}
}
  • 结果

image-20210223145341151

  • User修改内容
package com.kuang.pojo;import org.springframework.stereotype.Component;@Component
public class User {public String name;
}
  • 结果:

image-20210223145649487

1.属性注入

使用注解注入属性

  • User修改内容。可以不用提供set方法,直接在直接名上添加@value(“值”)
// 加上了注解:@Value("kuangshen")package com.kuang.pojo;import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;@Component
public class User {@Value("kuangshen")public String name;
}
  • 结果:

image-20210223145920982

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

  • User修改内容

// 修改了@Value("kuangshen")的位置,增加了set方法。package com.kuang.pojo;import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;@Component
public class User {public String name;@Value("kuangshen222")public void setName(String name) {this.name = name;}
}
  • 结果:

image-20210223150243844

2.衍生注解

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

@Component三个衍生注解

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

  • @Controller:web层
  • @Service:service层
  • @Repository:dao层

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

  • com.kuang.dao中新建UserDao的class文件
package com.kuang.dao;import org.springframework.stereotype.Repository;@Repository
public class UserDao {}
  • com.kuang.service中新建UserService的class文件
package com.kuang.service;import org.springframework.stereotype.Service;@Service
public class UserService {
}
  • com.kuang.controller中新建UserController的class文件
package com.kuang.controller;import org.springframework.stereotype.Controller;@Controller
public class UserController {
}
  • applicationContext.xml文件修改内容
    <context:component-scan base-package="com.kuang"/><context:annotation-config/>
<?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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsd"><!----><context:component-scan base-package="com.kuang"/><context:annotation-config/></beans>
3.自动装配注解

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

4.作用域

@scope

  • singleton:默认的,Spring会采用单例模式创建这个对象。关闭工厂 ,所有的对象都会销毁。
  • prototype:多例模式。关闭工厂 ,所有的对象不会销毁。内部的垃圾回收机制会回收
@Controller("user")
@Scope("prototype")
public class User {@Value("秦疆")public String name;
}

小结

XML与注解比较

  • XML可以适用任何场景 ,结构清晰,维护方便
  • 注解不是自己提供的类使用不了,开发简单方便

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

  • xml管理Bean
  • 注解完成属性注入
  • 使用过程中, 可以不用扫描,扫描是为了类上的注解
<context:annotation-config/>  

作用:

  • 进行注解驱动注册,从而使注解生效
  • 用于激活那些已经在spring容器里注册过的bean上面的注解,也就是显示的向Spring注册
  • 如果不扫描包,就需要手动配置bean
  • 如果不加注解驱动,则注入的值为null!

[15、使用JavaConfig实现配置]

5.基于Java类进行配置Spring

使用这种方式可以完全替换掉xml文件的配置。全权交给java来做。

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

  • 新建一个maven项目 spring-07-appconfig

image-20210223153330964

  • 新建com.kuang.pojo包,在其中新建User的class文件。
package com.kuang.pojo;public class User {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +'}';}
}
  • 新建一个com.kuang.config包,在其中新建KuangConfig文件
package com.kuang.config;import com.kuang.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class KuangConfig {@Beanpublic User getUser() {return new User();}
}
  • com.kuang.pojo包中的User文件增加内容:
@Component@Value("QINJIANG")
package com.kuang.pojo;import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;@Component
public class User {private String name;public String getName() {return name;}@Value("QINJIANG")public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +'}';}
}
  • test/java中新建MyTest
import com.kuang.config.KuangConfig;
import com.kuang.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class MyTest {public static void main(String[] args) {ApplicationContext context = new AnnotationConfigApplicationContext(KuangConfig.class);User getUser = (User) context.getBean("getUser");System.out.println(getUser.getName());}
}
  • 结果:

image-20210223154846125

image-20210223160332809

  • 下图中的两份内容的名字必须相同。

image-20210223160747619

  • KuangConfig代码,增加了注释。
package com.kuang.config;import com.kuang.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;@Configuration // 因为他本身就是一个@Component,他也会被spring容器托管,注册到容器中,@Configuration代表这是一个配置类,就和我们之前看的beans.xml是一样的。
@ComponentScan("com.kuang.pojo")
public class KuangConfig {// 注册一个bean,就相当于我们之前写的一个bean标签。// 这个方法的名字,就相当于bean标签中的id属性// 这个方法的返回值,就相当于bean标签中的class属性。@Beanpublic User getUser() {return new User();}
}
  • User增加注释。实体类代码
package com.kuang.pojo;import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;// 这里的注解的意思是,这个类被spring接管了,注册到了容器中。
@Component
public class User {private String name;public String getName() {return name;}@Value("QINJIANG") // 属性注入值public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +'}';}
}
  • com.kuang.config中新建一个KuangConfig2的class文件。

  • KuangConfig中增加内容:配置文件代码:
@Import(KuangConfig2.class)
package com.kuang.config;import com.kuang.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;@Configuration // 因为他本身就是一个@Component,他也会被spring容器托管,注册到容器中,@Configuration代表这是一个配置类,就和我们之前看的beans.xml是一样的。
@ComponentScan("com.kuang.pojo")
@Import(KuangConfig2.class)
public class KuangConfig {// 注册一个bean,就相当于我们之前写的一个bean标签。// 这个方法的名字,就相当于bean标签中的id属性// 这个方法的返回值,就相当于bean标签中的class属性。@Beanpublic User getUser() {return new User();}
}
  • 测试类:
import com.kuang.config.KuangConfig;
import com.kuang.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class MyTest {public static void main(String[] args) {ApplicationContext context = new AnnotationConfigApplicationContext(KuangConfig.class);User getUser = (User) context.getBean("getUser");System.out.println(getUser.getName());}
}

这种纯java的配置方式,在springboot中随处可见。

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


  • 新建springboot项目

image-20210223163159382

image-20210223163243855

  • 他会自动下载很多的东西。

  • 删掉阴影部分内容

image-20210223163629346

[17、静态代理模式]

10 代理模式

代理模式是AOP的底层

【Spring AOP Spring MVC】面试必问

代理模式的分类:

  • 静态代理
  • 动态代理

代理模式的图形表示:

img

10.1 静态代理

角色分析:

  • 抽象角色:一般会使用接口或者抽象类来实现
  • 真实角色:被代理的角色
  • 代理角色:代理真实角色,代理真实角色后,一般会做一些附属操作
  • 客户:访问代理对象的人。

  • 新建maven项目 spring-08-proxy
  • 在src/main/java中新建包com.kuang.demo01。在其中新建一个rent接口文件
package com.kuang.demo01;// 租房
public interface Rent {public void rent();
}
  • 包com.kuang.demo01中新建一个Host的class文件。
package com.kuang.demo01;// 房东
public class Host implements Rent {@Overridepublic void rent() {System.out.println("房东要出租房子");}
}
  • 包com.kuang.demo01中新建一个Client的class文件。
package com.kuang.demo01;public class Client {public static void main(String[] args) {Host host = new Host();host.rent();}
}
  • 运行Client,结果为:

image-20210223170338566

  • 新建一个代理角色,Proxy的class文件。
package com.kuang.demo01;public class Proxy {private Host host;public Proxy() {}public Proxy(Host host) {this.host = host;}
}
package com.kuang.demo01;public class Proxy implements Rent {private Host host;public Proxy() {}public Proxy(Host host) {this.host = host;}@Overridepublic void rent() {host.rent();}
}
  • client代码:
package com.kuang.demo01;public class Client {public static void main(String[] args) {Host host = new Host();// 代理Proxy proxy = new Proxy(host);proxy.rent();}
}
  • 运行client代码

image-20210223171119684

  • Proxy.java的代码
package com.kuang.demo01;public class Proxy implements Rent {private Host host;public Proxy() {}public Proxy(Host host) {this.host = host;}public void rent() {seeHouse();host.rent();hetong();fare();}// 看房public void seeHouse() {System.out.println("中介带你去看房");}// 收中介费public void fare() {System.out.println("中介收中介费");}// 收中介费public void hetong() {System.out.println("签合同");}
}
  • 运行Client文件,结果为:

image-20210223171653260

代码步骤:

1、接口。Rent接口程序

package com.kuang.demo01;// 租房
public interface Rent {public void rent();
}

2、真实角色。Host。房东。

package com.kuang.demo01;// 房东
public class Host implements Rent {@Overridepublic void rent() {System.out.println("房东要出租房子");}
}

3、代理角色。Proxy

package com.kuang.demo01;public class Proxy implements Rent {private Host host;public Proxy() {}public Proxy(Host host) {this.host = host;}public void rent() {seeHouse();host.rent();hetong();fare();}// 看房public void seeHouse() {System.out.println("中介带你去看房");}// 收中介费public void fare() {System.out.println("中介收中介费");}// 收中介费public void hetong() {System.out.println("签合同");}
}

4、客户端访问代理角色

package com.kuang.demo01;public class Client {public static void main(String[] args) {Host host = new Host();// 代理Proxy proxy = new Proxy(host);proxy.rent();}
}

10.1 静态代理

代理模式的好处:

  • 可以使真实角色的操作更加纯粹,不用去关注一些公共的业务
  • 公共业务交给代理角色,实现了业务的分工。
  • 公共业务发生扩展的时候,方便集中管理。

缺点:

  • 一个真实角色会产生一个代理类,代码量会翻倍

[P18 静态代理再理解]

10.2 加深理解

聊聊AOP

  • 在src/main/java中新建包com.kuang.demo02。在其中新建接口文件UserService
package com.kuang.demo02;public interface UserService {public void add();public void delete();public void update();public void query();
}
  • 包com.kuang.demo02中新建class文件UserServiceImpl
package com.kuang.demo02;// 真实对象
public class UserServiceImpl implements UserService {public void add() {System.out.println("add");}public void delete() {System.out.println("delete");}public void update() {System.out.println("update");}public void query() {System.out.println("query");}
}
  • client修改内容:
package com.kuang.demo02;public class Client {public static void main(String[] args) {UserServiceImpl userService = new UserServiceImpl();userService.add();}
}
  • 新建一个UserServiceProxy.java的文件
package com.kuang.demo02;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.add();}public void update() {log("update");userService.add();}public void query() {log("query");userService.add();}// 日志方法public void log(String msg) {System.out.println("【Debug】使用了" + msg + "方法");}
}
  • client修改代码
package com.kuang.demo02;public class Client {public static void main(String[] args) {UserServiceImpl userService = new UserServiceImpl();UserServiceProxy proxy = new UserServiceProxy();proxy.setUserService(userService);proxy.add();}
}
  • 运行client的结果

image-20210223205618843

  • client修改代码
package com.kuang.demo02;public class Client {public static void main(String[] args) {UserServiceImpl userService = new UserServiceImpl();UserServiceProxy proxy = new UserServiceProxy();proxy.setUserService(userService);proxy.delete();}
}
  • 运行client的结果

image-20210223205749047

代理模式的优点,不改变原有代码,增加业务功能。


聊聊AOP

image-20210223210233841

[19、动态代理详解] 前10min没听懂是啥。走神了。

10.3 动态代理

动态代理和静态代理角色一样

动态代理是动态生成的,不是我们直接写好的。

动态代理分为两大类:基于接口的动态代理,基于类的动态代理

基于接口–jdk动态代理 【我们在这里使用】

基于类:cglib

java字节码实现:javasis

需要了解两个类:Proxy 代理, InvocationHandler 调用处理程序

jdk api 1.8_google 文档

InvocationHandler

动态代理的好处:

一个动态代理类代理的是一个接口,一般就是对应的一类业务

一个动态代理类可以代理多个类,

  • 在com.kuang中新建一个包demo03,拷贝demo01的Host和Rent文件。

  • 在com.kuang.demo03中新建一个ProxyInvocationHandler的class文件。

package com.kuang.demo03;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;// 可以用这个类,自动生成代理类。
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);}// 此处的作用是处理代理实例,并返回结果public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 动态代理的本质是使用反射机制实现Object result = method.invoke(rent, args);return result;}
}
  • 在com.kuang.demo03中新建一个Client文件。
package com.kuang.demo03;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就是动态生成。我们并没有写。proxy.rent();}
}
  • 运行Client结果

image-20210223213630650

  • ProxyInvocationHandler的class文件修改内容如下:
package com.kuang.demo03;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;// 可以用这个类,自动生成代理类。
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);}// 此处的作用是处理代理实例,并返回结果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结果

image-20210223214441510


  • 新建一个com.kuang.demo04的包,拷贝ProxyInvocationHandler文件。
package com.kuang.demo04;import com.kuang.demo03.Rent;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;// 可以用这个类,自动生成代理类。
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);}// 此处的作用是处理代理实例,并返回结果public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 动态代理的本质是使用反射机制实现Object result = method.invoke(target, args);return result;}
}
  • 新建一个Client的class文件
package com.kuang.demo04;import com.kuang.demo02.UserService;
import com.kuang.demo02.UserServiceImpl;public class Client {public static void main(String[] args) {// 真实角色UserServiceImpl userService = new UserServiceImpl();// 代理角色,不存在ProxyInvocationHandler pih = new ProxyInvocationHandler();// 通过调用程序处理角色来处理我们要调用的接口对象;设置要代理的对象。pih.setTarget(userService);UserService proxy = (UserService) pih.getProxy();// 这roxy就是动态生成。我们并没有写。proxy.delete();}
}
  • Client运行结果:

image-20210223220301121

  • 增加一个日志功能。ProxyInvocationHandler添加内容:
 //日志功能public void log(String msg) {System.out.println("执行了" + msg + "方法");}
package com.kuang.demo04;import com.kuang.demo03.Rent;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;// 可以用这个类,自动生成代理类。
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);}// 此处的作用是处理代理实例,并返回结果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 msg) {System.out.println("执行了" + msg + "方法");}
}
  • 运行Client程序

image-20210223221018896

动态代理的好处:

一个动态代理类代理的是一个接口,一般就是对应的一类业务

一个动态代理类可以代理多个类。代码量减少了很多。

image-20210223221435816


这篇关于星期二 2021年2月23日 spring 12-19的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/283256

相关文章

分布式锁在Spring Boot应用中的实现过程

《分布式锁在SpringBoot应用中的实现过程》文章介绍在SpringBoot中通过自定义Lock注解、LockAspect切面和RedisLockUtils工具类实现分布式锁,确保多实例并发操作... 目录Lock注解LockASPect切面RedisLockUtils工具类总结在现代微服务架构中,分布

Java使用Thumbnailator库实现图片处理与压缩功能

《Java使用Thumbnailator库实现图片处理与压缩功能》Thumbnailator是高性能Java图像处理库,支持缩放、旋转、水印添加、裁剪及格式转换,提供易用API和性能优化,适合Web应... 目录1. 图片处理库Thumbnailator介绍2. 基本和指定大小图片缩放功能2.1 图片缩放的

Spring Boot集成/输出/日志级别控制/持久化开发实践

《SpringBoot集成/输出/日志级别控制/持久化开发实践》SpringBoot默认集成Logback,支持灵活日志级别配置(INFO/DEBUG等),输出包含时间戳、级别、类名等信息,并可通过... 目录一、日志概述1.1、Spring Boot日志简介1.2、日志框架与默认配置1.3、日志的核心作用

破茧 JDBC:MyBatis 在 Spring Boot 中的轻量实践指南

《破茧JDBC:MyBatis在SpringBoot中的轻量实践指南》MyBatis是持久层框架,简化JDBC开发,通过接口+XML/注解实现数据访问,动态代理生成实现类,支持增删改查及参数... 目录一、什么是 MyBATis二、 MyBatis 入门2.1、创建项目2.2、配置数据库连接字符串2.3、入

Springboot项目启动失败提示找不到dao类的解决

《Springboot项目启动失败提示找不到dao类的解决》SpringBoot启动失败,因ProductServiceImpl未正确注入ProductDao,原因:Dao未注册为Bean,解决:在启... 目录错误描述原因解决方法总结***************************APPLICA编

深度解析Spring Security 中的 SecurityFilterChain核心功能

《深度解析SpringSecurity中的SecurityFilterChain核心功能》SecurityFilterChain通过组件化配置、类型安全路径匹配、多链协同三大特性,重构了Spri... 目录Spring Security 中的SecurityFilterChain深度解析一、Security

SpringBoot多环境配置数据读取方式

《SpringBoot多环境配置数据读取方式》SpringBoot通过环境隔离机制,支持properties/yaml/yml多格式配置,结合@Value、Environment和@Configura... 目录一、多环境配置的核心思路二、3种配置文件格式详解2.1 properties格式(传统格式)1.

Apache Ignite 与 Spring Boot 集成详细指南

《ApacheIgnite与SpringBoot集成详细指南》ApacheIgnite官方指南详解如何通过SpringBootStarter扩展实现自动配置,支持厚/轻客户端模式,简化Ign... 目录 一、背景:为什么需要这个集成? 二、两种集成方式(对应两种客户端模型) 三、方式一:自动配置 Thick

Spring WebClient从入门到精通

《SpringWebClient从入门到精通》本文详解SpringWebClient非阻塞响应式特性及优势,涵盖核心API、实战应用与性能优化,对比RestTemplate,为微服务通信提供高效解决... 目录一、WebClient 概述1.1 为什么选择 WebClient?1.2 WebClient 与

Java.lang.InterruptedException被中止异常的原因及解决方案

《Java.lang.InterruptedException被中止异常的原因及解决方案》Java.lang.InterruptedException是线程被中断时抛出的异常,用于协作停止执行,常见于... 目录报错问题报错原因解决方法Java.lang.InterruptedException 是 Jav