星期二 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

相关文章

Java实现Excel与HTML互转

《Java实现Excel与HTML互转》Excel是一种电子表格格式,而HTM则是一种用于创建网页的标记语言,虽然两者在用途上存在差异,但有时我们需要将数据从一种格式转换为另一种格式,下面我们就来看看... Excel是一种电子表格格式,广泛用于数据处理和分析,而HTM则是一种用于创建网页的标记语言。虽然两

java图像识别工具类(ImageRecognitionUtils)使用实例详解

《java图像识别工具类(ImageRecognitionUtils)使用实例详解》:本文主要介绍如何在Java中使用OpenCV进行图像识别,包括图像加载、预处理、分类、人脸检测和特征提取等步骤... 目录前言1. 图像识别的背景与作用2. 设计目标3. 项目依赖4. 设计与实现 ImageRecogni

Java中Springboot集成Kafka实现消息发送和接收功能

《Java中Springboot集成Kafka实现消息发送和接收功能》Kafka是一个高吞吐量的分布式发布-订阅消息系统,主要用于处理大规模数据流,它由生产者、消费者、主题、分区和代理等组件构成,Ka... 目录一、Kafka 简介二、Kafka 功能三、POM依赖四、配置文件五、生产者六、消费者一、Kaf

Java访问修饰符public、private、protected及默认访问权限详解

《Java访问修饰符public、private、protected及默认访问权限详解》:本文主要介绍Java访问修饰符public、private、protected及默认访问权限的相关资料,每... 目录前言1. public 访问修饰符特点:示例:适用场景:2. private 访问修饰符特点:示例:

详解Java如何向http/https接口发出请求

《详解Java如何向http/https接口发出请求》这篇文章主要为大家详细介绍了Java如何实现向http/https接口发出请求,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 用Java发送web请求所用到的包都在java.net下,在具体使用时可以用如下代码,你可以把它封装成一

SpringBoot使用Apache Tika检测敏感信息

《SpringBoot使用ApacheTika检测敏感信息》ApacheTika是一个功能强大的内容分析工具,它能够从多种文件格式中提取文本、元数据以及其他结构化信息,下面我们来看看如何使用Ap... 目录Tika 主要特性1. 多格式支持2. 自动文件类型检测3. 文本和元数据提取4. 支持 OCR(光学

Java内存泄漏问题的排查、优化与最佳实践

《Java内存泄漏问题的排查、优化与最佳实践》在Java开发中,内存泄漏是一个常见且令人头疼的问题,内存泄漏指的是程序在运行过程中,已经不再使用的对象没有被及时释放,从而导致内存占用不断增加,最终... 目录引言1. 什么是内存泄漏?常见的内存泄漏情况2. 如何排查 Java 中的内存泄漏?2.1 使用 J

JAVA系统中Spring Boot应用程序的配置文件application.yml使用详解

《JAVA系统中SpringBoot应用程序的配置文件application.yml使用详解》:本文主要介绍JAVA系统中SpringBoot应用程序的配置文件application.yml的... 目录文件路径文件内容解释1. Server 配置2. Spring 配置3. Logging 配置4. Ma

Java 字符数组转字符串的常用方法

《Java字符数组转字符串的常用方法》文章总结了在Java中将字符数组转换为字符串的几种常用方法,包括使用String构造函数、String.valueOf()方法、StringBuilder以及A... 目录1. 使用String构造函数1.1 基本转换方法1.2 注意事项2. 使用String.valu

java脚本使用不同版本jdk的说明介绍

《java脚本使用不同版本jdk的说明介绍》本文介绍了在Java中执行JavaScript脚本的几种方式,包括使用ScriptEngine、Nashorn和GraalVM,ScriptEngine适用... 目录Java脚本使用不同版本jdk的说明1.使用ScriptEngine执行javascript2.