Spring第两天学习笔记

Spring第两天学习笔记,第1张

org.springframework spring-webmvc 5.3.9 1、spring 1.1、简介
  • spring:春天 ===>给软件行业带来了春天

  • 2002年,首次推出了spring框架的雏形:interface21

  • Spring框架即以interface21框架为基础,经过重新设计,并不断丰富其内涵,于2004年3月24日,发布了1.0正式版。

  • [Rod Johnson](https://baike.baidu.com/item/Rod Johnson/1423612),Spring Framework创始人,著名作者,它是悉尼大学音乐学的博士

  • Spring是面向切面编程(AOP)和控制反转(IoC)的容器框架。

  • spring设计理念:使现有的技术更加容易使用,本社是一个大杂烩,整合了现有的技术框架

  • SSH:struct2 + spring + hibernate

  • SSM:springmvc + spring + mybatis

官网:https://spring.io/projects/spring-framework

官方下载地址:https://repo.spring.io/ui/native/release/org/springframework/spring

GitHub:https://github.com/spring-projects/spring-framework


<dependency>
    <groupId>org.springframeworkgroupId>
    <artifactId>spring-webmvcartifactId>
    <version>5.3.19version>
dependency>


<dependency>
    <groupId>org.springframeworkgroupId>
    <artifactId>spring-jdbcartifactId>
    <version>5.3.19version>
dependency>

导webmvc,maven就会帮我们导入其它的所依赖的包

1.2、优点
  • spring是一个开源的免费的框架(容器)
  • spring是一个轻量级的、非入侵式的框架
  • 两大特性:控制反转(IOC)、面向切面编程(AOP)
  • 支持事务的处理,对框架整合的支持

总结:spring就是一个轻量级的控制反转和面向切面编程的框架

1.3、组成

1.4、拓展

在spring的官网有这个介绍:现代化的Java开发,就是基于spring的开发

  • Spring Boot

    • 一个快速开发的脚手架;

    • 基于Spring Boot可以快速开发单个微服务;

    • 约定大于配置。

  • Spring Cloud

    • Spring Cloud是基于Spring Boot实现的;

因为现在大多数公司都在使用Spring Boot进行快速开发,学习Spring Boot的前提,需要完全掌握Spring及SpringMVC。承上启下的作用

弊端:发展了太久之后,违背了原来的理念!配置十分繁琐,人称:“配置地狱”。

2、IOC理论推导

原来业务的步骤:

  1. UserDao 接口
  2. UserDaoImpl 实现类
  3. UserService 业务接口
  4. UserServiceImpl 业务实现类

在我们之前的业务中,用户的需求可能会影响我们原来的代码,我们需要根据用户的需求去修改原代码。如果程序代码量足够大,修改一次的成本代价很大。

已经发生了革命性的变化!

public class UserServiceImpl implements UserService{
/*
    //使用组合将UserDao引到service里面
    private UserDao userDao = new UserDaoImpl();
*/

    private UserDao userDao;
    //将new UserDaoImpl();隐藏,利用set进行动态实现值的注入  ===>  IOC控制反转
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public void getUser() {
        //真正是业务层调用dao层的方法
        userDao.getUser();
    }
}
  • 之前,程序是主动创建对象,控制权在程序员手里
  • 现在,利用set进行动态实现值的注入,程序不在具有主动性,而是变成了被动的接收对象

这种思想,从本质上解决了问题,我们程序员不用再去管理对象的创建。系统的耦合性大大降低!可以更加专注于业务的实现!!这是IOC的原型。

2.1、IOC本质

IOC是一种思想,而依赖注入(DI)只是它的一种实现。

Spring过程:Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从IOC容器中取出需要的对象。XML配置Bean时,Bean的定义信息和实现是分离的,而是采用注解的方式将两者合为一体,最新版的Spring已经可以零配置实现IOC,主要是因为Bean的定义信息以注解的形式定义在实现类中。

控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式,Spring中实现控制反转的是IOC容器,其实现方法是依赖注入(Dependency Injection,DI)。

3、Hello Spring

实体类

public class Hello {
    private String str;

    @Override
    public String toString() {
        return "Hello{" +
                "str='" + str + '\'' +
                '}';
    }

    public String getStr() {
        return str;
    }

    public void setStr(String str) {
        this.str = str;
    }
}

spring配置文件


<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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <bean id="hello" class="com.bei.pojo.Hello">
        <property name="str" value="Spring"/>
    bean>

beans>

测试类

public class MyTest {
    @Test
    public void hello(){
        //获取spring的上下文对象
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        //我们的对象现在都在spring中管理了,我们要使用直接去里面取出来
        Hello hello = (Hello) context.getBean("hello");
        System.out.println(hello);
    }
}

思考问题?

  • Hello对象是谁创建的?
    hello对象是由Spring创建的.

  • Hello 对象的属性是怎么设置的?
    hello对象的属性是由Spring容器设置的。

这个过程就叫控制反转:
控制:谁来控制对象的创建,传统应用程序的对象是由程序本身控制创建的,使用Spring后,对象是由Spring来创建的.
反转(ioc):程序本身不创建对象,而变成被动的接收对象.
依赖注入(di):就是利用set方法来进行注入的.
IOC是一种编程思想,由主动的编程变成被动的接收.可以通过new ClassPathXmlApplicationContext()去浏览一下底层源码。

OK,到了现在,我们彻底不用在程序中改动了,要实现不同的 *** 作,只需要在xml配置文件中进行修改,所谓的IOC,说白了就是:对象由Spring来创建,管理,装配

4、IOC创建对象的方式
  1. 默认使用无参构造创建对象

  2. 假设我们要使用有参构造创建对象

    • 下标赋值

      
      <bean id="user" class="com.bei.pojo.User">
          <constructor-arg index="0" value="一北北"/>
      bean>
      
    • 类型赋值

      
      <bean id="user" class="com.bei.pojo.User">
         <constructor-arg type="java.lang.String" value="一北北"/>
      bean>
      
    • 参数名

      
      <bean id="user" class="com.bei.pojo.User">
         <constructor-arg name="name" value="一北北"/>
      bean>
      

总结:在配置文件加载时,spring容器中管理的对象就已经初始化了

5、Spring配置 5.1、别名

<alias name="user" alias="alias"/>
@Test
public void test(){
    ApplicationContext Context = new ClassPathXmlApplicationContext("beans.xml");
    //User user = (User)Context.getBean("user");
    User user = (User)Context.getBean("alias");
    user.show();
}
5.2、bean的配置

<bean id="user" class="com.bei.pojo.User" name="user1,user2;user3 u4">
    <property name="name" value="一北吧"/>
bean>
5.3、import

这个import,一般用于团队开发使用,它可以将多个配置文件,导入合并为一个

假设,现在项目中有多个人开发,这三个人负责不同的类开发。不同的类需要注册在不同的bean中,我们可以利用import将所有人的beans.xml合并为一个总的

  • beans1

  • beans2

  • beans3

  • applicationContext.xml

    <import resource="beans1.xml"/>
    <import resource="beans2.xml"/>
    <import resource="beans3.xml"/>
    

使用的时候,直接使用总的配置即可

6、依赖注入(DI) 6.1、构造器注入

前面已说,不再赘述

6.2、set方式注入【重点】
  • 依赖注入:set注入
    • 依赖:bean对象的创建依赖于容器
    • 注入:bean对象中的所有属性由容器来注入

【环境搭建】

  1. 复杂类型

    public class Address {
        private String address;
    
        public Address(String address) {
            this.address = address;
        }
    
        public Address() {
        }
    }
    
  2. 真实测试对象

    public class Student {
        private String name;
    
        private Address address;
    
        private String[] books;
        private List<String> hobbys;
        private Map<String,String> card;
        private Set<String> games;
        private String wife;
        private Properties info;
    }
    
  3. beans.xml

    
    <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
            https://www.springframework.org/schema/beans/spring-beans.xsd">
        
        <bean id="address" class="com.bei.pojo.Address"/>
    
        <bean id="student" class="com.bei.pojo.Student">
            
            <property name="name" value="一北"/>
            
            <property name="address" ref="address"/>
            
            <property name="books">
                <array>
                    <value>红楼梦value>
                    <value>西游记value>
                    <value>水浒传value>
                    <value>戏三国value>
                array>
            property>
            
            <property name="hobbys">
                <list>
                    <value>足球value>
                    <value>篮球value>
                    <value>排球value>
                    <value>码码value>
                list>
            property>
            
            <property name="card">
                <map>
                    <entry key="身份z" value="3290231212212122134"/>
                    <entry key="yhk" value="1910-2121-2129-2121"/>
                map>
            property>
            
            <property name="games">
                <set>
                    <value>LOLvalue>
                    <value>王者荣耀value>
                set>
            property>
            
            <property name="wife">
                <null/>
            property>
            
            <property name="info">
                <props>
                    <prop key="学号">3120002988prop>
                    <prop key="性别">prop>
                    <prop key="username">小李prop>
                    <prop key="password">abc123prop>
                props>
            property>
            
        bean>
    
    beans>
    
  4. 测试类

    @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
    
        Student student = (Student) context.getBean("student");
    
        System.out.println("student.getName() = " + student.getName());
    }
    
6.3、其它方式注入

我们可以使用p、c命名空间注入

官方解释:

配置使用:


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    
    <bean id="user" class="com.bei.pojo.User" p:name="一北" p:age="18"/>
    
    <bean id="user2" class="com.bei.pojo.User" c:name="一北" c:age="20"/>

beans>

测试:

@Test
public void test2() {
    ApplicationContext context = new ClassPathXmlApplicationContext("UserBeans.xml");
    User user = context.getBean("user2", User.class);
    System.out.println("user = " + user);
}

【注意】p、c命名空间不能直接使用,需要导入xml约束

6.4、bean的作用域(scopes)
ScopeDescription
singleton(Default) Scopes a single bean definition to a single object instance for each Spring IoCcontainer.
prototypeScopes a single bean definition to any number of object instances.
requestScopes a single bean definition to the lifecycle of a single HTTP request. That is,each HTTP request has its own instance of a bean created off the back of a single beandefinition. Only valid in the context of a web-aware SpringApplicationContext.
sessionScopes a single bean definition to the lifecycle of an HTTPSession. Only valid inthe context of a web-aware SpringApplicationContext.
applicationScopes a single bean definition to the lifecycle of aServletContext. Only valid inthe context of a web-aware SpringApplicationContext.
websocketScopes a single bean definition to the lifecycle of aWebSocket. Only valid inthe context of a web-aware SpringApplicationContext.
  1. 单例模式[singleton](Spring的默认机制)

    <bean id="user2" class="com.bei.pojo.User" c:name="一北" c:age="20" scope="singleton"/>
    
  2. 原型模式[prototype]:每次从容器中get的时候都会产生一个新对象

    <bean id="accountService" class="com.something.DefaultAccountService" scope="prototype"/>
    
  3. 剩下的request、session、application。只能在web开发中使用到

7、bean的自动装配
  • 自动装配时Spring满足bean依赖的一种方式;

  • Spring会在上下文中自动寻找,并给bean装配属性

    在Spring中有三种装配方式

  1. 在xml中显示地配置
  2. 在java中显示配置
  3. 隐式地自动装配bean【重要】
7.1、测试
  1. 环境搭建:一个人有两个宠物
7.2、byName自动装配

    <bean id="person" class="com.bei.pojo.Person" autowire="byName" >
        <property name="name" value="一北宝贝"/>
    bean>
7.3、byType自动装配
<bean id="cat" class="com.bei.pojo.Cat"/>
<bean id="dog" class="com.bei.pojo.Dog"/>
 <bean id="person" class="com.bei.pojo.Person" autowire="byType" >
        <property name="name" value="一北宝贝"/>
    bean>

【小结】

  • 在byName的时候,必须保证所有bean的id唯一,且要和自动注入的属性的set方法后的值一致
  • 在byType的时候,必须保证所有bean的class唯一,且要和自动注入的属性的类型一致
7.4、注解实现自动装配

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

The introduction of annotation-based configuration raised the question of whether thisapproach is “better” than XML.

使用注解之前必做:

  1. 导入约束:context约束

  2. 配置注解的支持:【重点】

    
    <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
            https://www.springframework.org/schema/context/spring-context.xsd">
    	
        
        <context:annotation-config/>
    
    beans>
    

    @Autowired

    直接在用在复合类的属性(或相应的set方法)上即可,使用注解甚至不需要写set方法,因为注解是用反射来实现的。

    @Data
    public class Person {
        private String name;
        @Autowired
        private Cat cat;
        @Autowired
        private Dog dog;
    }
    

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

    常识:

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

    测试代码:

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

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

    @Data
    public class Person {
        private String name;
    
        @Autowired
        @Qualifier("cat")
        private Cat cat;
        @Autowired
        private Dog dog;
    }
    

    @Resource注解

    @Data
    public class Person {
        private String name;
        @Resource(name = "cat")
        private Cat cat;
        @Resource
        private Dog dog;
    }
    

【小结】@Resource和@Autowired的区别

  • 都是用来自动装配的,都可以放在属性字段上
  • @Autowired 通过byType的方式实现,而且必须要求这个对象存在【常用】
  • @Resource 默认通过byName的方式实现,如果找不到名字,则用byType实现,若两个都找不到,则报错【常用】
  • 执行顺序不同,@Autowired 通过byType的方式实现,类型-名字。@Resource 默认通过byName的方式实现,名字-类型
8、使用注解开发

在Spring 4之后,如果要使用注解开发,必须要先保证AOP的包已经导入

使用注解需要导入context约束,增加注解的支持


<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
        https://www.springframework.org/schema/context/spring-context.xsd">

    
    <context:annotation-config/>

beans>
  1. bean

  2. 属性如何注入

    @Component //等价于  
    public class User {
        //相当于     
        @Value("一北宝贝")//优先级更高
        public String name="一北";
    
    }
    

    其中@Value也可以放在相应的set方法上

  3. 衍生的注解 – 都会将修饰的类注册到IOC容器里面

    • pojo 【@Component】 有几个衍生的注解,我们在web开发中,会按照mvc三层架构分层

    • dao 【@Repository】

    • service 【@Service】

    • controller 【@Controller】

    【注】:这四个注解的功能是一样的,都是代表将某个类注册到Spring中,装配bean

  4. 自动装配

    • @Autowired:自动装配类型,名字
      如果Autowired不能唯一自动装配上属性,则需要通过@Qualifier(“value”)
    • @Resource:自动装配名字,类型
    • @Nullable: 若一个字段标记了该注解,则这个字段可以为null
  5. 作用域

    @Component //等价于  
    @Scope("prototype")
    public class User {
        //相当于     
        @Value("一北宝贝")//优先级更高
        public String name="一北";
    
    }
    
  6. 小结

    xml与注解:

    • xml具有普适性,适用于任何场合,维护简单方便;
    • 注解不是自己的类使用不了,维护相对复杂;

    xml与注解最佳搭配:

    • xml用来管理bean;

    • 注解只负责完成属性的注入;

    • 我们在使用的过程中,只需要注意一个问题,若要让注解生效,就需要开启注解的支持,即下面两句话

      
      <context:annotation-config/>
      
      <context:component-scan base-package="com.bei"/>
      
9、 使用Java的方式配置Spring

我们现在可以完全不使用Spring的xml配置了,全部交给Java来做

JavaConfig是Spring的一个子项目,在Spring 4之后,它成为了一个核心功能

  • 实体类
@Data
//这个注解就是说明这个类被Spring接管了,已注册容器中
@Component
public class User {
    private String name;

    public String getName() {
        return name;
    }
    @Value("一北宝贝")//属性注入值
    public void setName(String name) {
        this.name = name;
    }
}
  • 配置类
@Configuration 
//这个同样会被Spring容器托管,因为它本质上也是一个@Component
//@Configuration代表这个类是一个配置类,和我们之前看的beans.xml等价
@ComponentScan("com.bei.pojo")
@Import(BeiConfig2.class)
public class BeiConfig {
    //注册一个bean,等价于bean标签
    //方法名等价于bean标签中的id属性
    //方法的返回值等价于bean标签中的class属性
    @Bean
    public User myUser(){
        return new User();
    }
}
  • 测试类
public class MyTest {
    @Test
    public void test(){
        //若完全使用注解(配置类)的方式去做,我们就只能通过AnnotationConfig 上下文来获取容器,通过配置类的class对象加载
        ApplicationContext context = new AnnotationConfigApplicationContext(BeiConfig.class);

        User user = context.getBean("myUser",User.class);
        System.out.println(user.getName());
    }
}

这种纯Java的配置方式在SpringBoot中随处可见

10、代理模式

为什么需要学习代理模式?

因为这就是SpringAOP的底层!【SpringAOP 和 SpringMVC】

代理模式的分类:

  • 静态代理:
  • 动态代理:

10.1、静态代理

角色分析:

  • 抽象角色:一般会用接口或者抽象类来解决
  • 真实角色:被代理的角色
  • 代理角色:代理真实角色,代理真实角色后,我们一般会做一些附属 *** 作
  • 客户:访问代理对象的人!

代码实现:

  1. 抽象接口:

    public interface Rent {
        public void rent();
    }
    
  2. 真实角色:

    public class Host implements Rent{
        private String name;
    
        public Host(String name) {
            this.name = name;
        }
    
        @Override
        public void rent() {
            System.out.println("房东"+name+"出租房子");
        }
    }
    
  3. 代理角色:

    public class Proxy implements Rent{
        private Host host;
        
        public Proxy(Host host) {
            this.host = host;
        }
    
        @Override
        public void rent() {
            System.out.println("代理人 *** 作**************");
            host.rent();
            System.out.println("**********************");
        }
        public void showHouse(){
            System.out.println("中介带你看房");
        }
    }
    
  4. 客户访问代理角色:

    public class Client {
        public static void main(String[] args) {
            Proxy proxy = new Proxy(new Host("贝贝"));
            proxy.showHouse();
            proxy.rent();
        }
    }
    
  5. 测试结果:

代理模式的好处:

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

代理模式的缺点:

  • 一个真实角色就会产生一个代理角色,代码量翻倍;但也不一定,有可能多个真实角色由同一个代理人代理
10.2、加深代理模式的理解

聊聊AOP:

代码

  1. 抽象接口:

    public interface UserService {
        public void add();
        public void del();
        public void update();
        public void query();
    }
    
  2. 真实类

    public class UserServiceImpl implements UserService{
    
        @Override
        public void add() {
            System.out.println("增加了一个用户");
        }
    
        @Override
        public void del() {
            System.out.println("删除了一个用户");
        }
    
        @Override
        public void update() {
            System.out.println("修改了一个用户");
        }
    
        @Override
        public void query() {
            System.out.println("查询了一个用户");
        }
    }
    
  3. 代理类

    public class UserServiceProxy implements UserService{
        private UserServiceImpl userService;
    
        //通过set一个组合类的方法来实现代理
        public void setUserService(UserServiceImpl userService) {
            this.userService = userService;
        }
    
        @Override
        public void add() {
            log("add");
            userService.add();
        }
    
        @Override
        public void del() {
            log("del");
            userService.del();
        }
    
        @Override
        public void update() {
            log("update");
            userService.update();
        }
    
        @Override
        public void query() {
            log("query");
            userService.query();
        }
        //日志方法
        public void log(String fun){
            System.out.println("[debug] 使用了"+fun+"方法");
        }
    }
    
  4. 客户访问代理类

    public class Client {
        public static void main(String[] args) {
            //创建一个真实类
            UserServiceImpl userService = new UserServiceImpl();
            //创建一个代理类
            UserServiceProxy userServiceProxy = new UserServiceProxy();
            //中介准备代理房东
            userServiceProxy.setUserService(userService);
            //中介实现代理后执行业务
            userServiceProxy.add();
        }
    }
    
10.3、动态代理
  • 动态代理和静态代理角色都一样
  • 动态代理的代理类是动态生成的,不是我们直接写好的
  • 动态代理分为两大类:基于接口的动态代理;基于类的动态代理
    • 基于接口: ——JDK 动态代理 【我们在这里使用】
    • 基于类:cglib
    • java字节码实现:javasist

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

通用万能动态代理代码实现:

  1. 抽象接口:

    public interface UserService {
        public void add();
        public void del();
        public void update();
        public void query();
    }
    
  2. 真实角色:

    public class UserServiceImpl implements UserService{
    
        @Override
        public void add() {
            System.out.println("增加了一个用户");
        }
    
        @Override
        public void del() {
            System.out.println("删除了一个用户");
        }
    
        @Override
        public void update() {
            System.out.println("修改了一个用户");
        }
    
        @Override
        public void query() {
            System.out.println("查询了一个用户");
        }
    }
    
  3. 调用处理程序类,用其生成代理类:

    //用这个类自动生成代理类
    public class ProxyInvocationHandler implements InvocationHandler {
    
        //被代理的接口
        private Object target;
    
        public void setTarget(Object target) {
            this.target = target;
        }
    
        //得到代理类
        public Object getProxy() {
                Object o = Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
            return o;
        }
    
        @Override//处理代理实例,并返回结果
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            log(method.getName());
            //动态代理的本质,就是使用反射的机制来实现的
            Object o = method.invoke(target, args);
            return o;
        }
        public void log(String msg){
            System.out.println("执行了"+msg+"方法");
        }
    }
    
  4. 客户访问代理角色:

    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();
    
            proxy.add();
    
        }
    }
    

通用动态代理类的具体化:

  1. 抽象接口:

    public interface Rent {
        public void rent();
    }
    
  2. 真实角色:

    public class Host implements Rent {
        private String name;
    
        public Host(String name) {
            this.name = name;
        }
    
        @Override
        public void rent() {
            System.out.println("房东"+name+"出租房子");
        }
    }
    
  3. 调用处理程序类,用其生成代理类:

    //用这个类自动生成代理类
    public class ProxyInvocationHandler implements InvocationHandler {
    
        //被代理的接口
        private Rent rent;
    
        public void setRent(Rent rent) {
            System.out.println("setRent方法");
            this.rent = rent;
        }
    
        //得到代理类
        public Object getProxy() {
            System.out.println("getProxy方法");
                Object o = Proxy.newProxyInstance(this.getClass().getClassLoader(), rent.getClass().getInterfaces(), this);
            return o;
        }
    
        @Override//处理代理实例,并返回结果
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("invoke方法");
            seeHouse();
            //动态代理的本质,就是使用反射的机制来实现的
            Object o = method.invoke(rent, args);
            return o;
        }
        public void seeHouse(){
            System.out.println("中介带客户看房子");
        }
    }
    
  4. 客户访问代理角色:

    public class Client {
        public static void main(String[] args) {
            //真实角色
            Host host = new Host("贝贝宝贝");
            //代理角色:现在没有
            //用代理调用处理程序生成一个代理类
            ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler();
            //通过调用处理程序角色来处理我们要调用的接口对象
            proxyInvocationHandler.setRent(host);//代理真实角色
    
            //这里的proxy代理实例就是动态生成的,我们并没有写
            Rent proxy = (Rent) proxyInvocationHandler.getProxy();
    
           /*调用顺序
            setRent方法:实现代理
            getProxy方法:获取代理
            invoke方法:调用代理
            */
            proxy.rent();
    
        }
    }
    

动态代理的好处:

  • 可以使真实角色的 *** 作更加纯粹,不用去关注一些公共的业务;
  • 公共的业务交给了代理角色!实现了业务的分工;
  • 公共业务发生拓展的时候,方便集中管理;
  • 一个动态代理类代理的是一个接口,对应的是一类业务;
  • 一个动态代理类可以代理多个类,只要是实现了同一个接口即可。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/876923.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-13
下一篇 2022-05-13

发表评论

登录后才能评论

评论列表(0条)

保存