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

相关文章

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

安卓链接正常显示,ios#符被转义%23导致链接访问404

原因分析: url中含有特殊字符 中文未编码 都有可能导致URL转换失败,所以需要对url编码处理  如下: guard let allowUrl = webUrl.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else {return} 后面发现当url中有#号时,会被误伤转义为%23,导致链接无法访问