框架学习 三 Spring 、02(maven,mybatis,spring,springmvc) 夹带设计模式

1bean作用域

bean的作用域有7种,最常用的**有单例和原型
还有request 、 session、 globalSession、 application、 websocket

singleton 单例

singleton是Spring容器默认的作用域,当Bean的作用域为singleton时,Spring容器就只会存在一个共享的Bean实例。singleton作用域对于无会话状态的Bean(如Dao 组件、Service组件)来说,是最理想的选择。

在配置文件声明bean 在容器只有一个唯一bean ,当每次获取都是同一个bean

``
singleton
1.在容器启动只创建一个 id 为student1 bean
2.并且放置在容器中,容器管理他的生命周期


propertype 原型

当用户向容器获取bean 时,容器才创建,容器只负责创建,不负责保存维护他的生命周期

1.用户向容器获取时 创建id student2对象
2.每次都创建新的对象
3.容器只负责帮我们创建 不会放置在容器中,不会管理bean 的生命周期 ,由用户自己负责




```1、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/beans http://www.springframework.org/schema/beans/spring-beans.xsd">


    <!--
       声明让容器创建一个 Student类型的bean  id student1

      scope="singleton"  容器创建bean scope 默认的 作用域是单例singleton
      singleton 1.在容器启动只创建一个 id 为student1 bean  2.并且放置在容器中,容器管理他的生命周期
    -->
    <bean id="student1" class="com.qfedu.entity.Student" scope="singleton">
        <property name="id" value="1000"></property>
        <property name="name" value="xiaoming"></property>
    </bean>

    <!--
        声明让容器创建bean 作用域prototype

        prototype 1.用户向容器获取时 创建id student2对象 2.每次都创建新的对象  3.容器只负责帮我们创建 不会放置在容器中,不会管理bean 的生命周期 ,由用户自己负责
    -->
    <bean  id="student2" class="com.qfedu.entity.Student" scope="prototype">

    </bean>


</beans>

2、测试

public class SingletonTest {

    public static void main(String[] args) {


        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("scope/singleton_bean.xml");


        Student student1_A = (Student) applicationContext.getBean("student1");
        System.out.println("student1_A:"+student1_A);

        Student student1_B = (Student) applicationContext.getBean("student1");
        System.out.println("student1_B:"+student1_B);

        System.out.println("student1_A == student1_B:"+(student1_A == student1_B));

        System.out.println("***************************************************");

        // 获取 原型的student2 当获取时 容器创建
        Student student2_A  = (Student) applicationContext.getBean("student2");
        System.out.println("student2_A:"+student2_A);


        // 第二次获取 原型的student2 当获取时 容器创建
        Student student2_B  = (Student) applicationContext.getBean("student2");
        System.out.println("student2_B:"+student2_B);

        System.out.println("student2_A== student2_B:"+(student2_A==student2_B));

    }
}

2.bean的生命周期

bean 的生老病死

单例的bean:随着容器的启动,bean 创建,容器并负责维护bean的生命周期

官方:
Spring容器可以管理singleton作用域的Bean的生命周期,在此作用域下,Spring能够精确的知道该Bean何时被创建,何时初始化完成,以及何时被销毁。

  • prototype

原型的bean: 容器启动时不创建bean,当用户获取时容器才创建bean,每次都是新的bean,容器不管理他的生命周期

官方:
prototype作用域的Bean,Spring只负责创建,当容器创建了Bean实例后,Bean的实例就交给客户端代码来管理,Spring容器将不再跟踪其生命周期。

1.在Student增加声明周期相关的方法

 /**
     * 初始化方法
     */
    public void  init(){

        System.out.println("对象初始化");
    }

    /**
     * 销毁方法
     */
    public void destroy(){
        System.out.println("对象销毁了");
    }

	<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">



    <!--
     init-method="init"  容器创建bean 时调用 初始化方法
     destroy-method="destroy"  当容器销毁时调用 销毁方法
    -->
    <bean id="student1" class="com.qfedu.entity.Student" scope="singleton"
          init-method="init" destroy-method="destroy" >
        <property name="id" value="1000"></property>
        <property name="name" value="xiaoming"></property>
    </bean>


    <!--
        声明 一个原型的bean  当用户获取时创建,容器只负责创建 不负责bean 的生命周期,由用户自己管理
        当容器销毁时 bean 的destroy 不会被容器调用
    -->
    <bean  id="student2" class="com.qfedu.entity.Student"
           scope="prototype" init-method="init" destroy-method="destroy"

    >   <property name="id" value="1000"></property>
        <property name="name" value="xiaohua"></property>

    </bean>



</beans>

测试

/**
 * bean生命周期 管理
 */
public class LifeTest {

    public static void main(String[] args) {


        System.out.println("容器启动");
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("life/life_bean.xml");


      Student student1 = (Student) applicationContext.getBean("student1");


        // 向容器获取原型  对象此时 触发原型的创建
        Student student2 = (Student) applicationContext.getBean("student2");

        // 显示调用容器的销毁方法  销毁前会将容器中所有的bean 先销毁, 调用bean 的destroy()
        applicationContext.destroy();
        System.out.println("容器销毁");

    }
}

3.bean的装配

什么是bean的装配

Bean的装配可以理解为依赖关系注入,Bean的装配方式就是Bean依赖注入的方式。

Spring容器支持多种形式的Bean的装配方式,如

1、基于XML的装配、

2、基于注解(Annotation)的装配

3、自动装配(其中最常用的是基于注解的装配)

一、基于xml装配(两种)

1、设置值装配
	1.必有有无参构造 

	2.必须有setter方法
2、构造方法装配
	1.必须有构造方法 

	2.使用<constructor-arg  进行初始化
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">



    <!--
         基于xml 
		setter 装配 设置值 必须由两个条件 :
		1.有无参构造 
		2.要有setter 方法 必不可少
    -->
    <bean id="student1"  class="com.qfedu.entity.Student">
        <property name="name" value="xiaoming"></property>
        <property name="id" value="1000"></property>

        <property name="courseList" >

            <list>
                <value>java</value>
                <value>c++</value>
                <value>python</value>
            </list>

        </property>

    </bean>


    <!--
        基于xml 
		构造方法的装配 初始化
        <constructor-arg 给构造参数 传数据
                index="0" 下标0 代表第一个参数
                value="1001" 第一个参数的值
    -->
    <bean id="student2" class="com.qfedu.entity.Student">

        <constructor-arg index="0" value="1001"></constructor-arg>
        <constructor-arg index="1" value="xiaohua"></constructor-arg>
        <constructor-arg index="2">
            <list>
                <value>java</value>
                <value>c++</value>
                <value>python</value>
            </list>
        </constructor-arg>
    </bean>



    <bean id="studentDao" class="com.qfedu.dao.impl.IStudentDaoImpl"></bean>


    <bean id="studentService" class="com.qfedu.service.StudentServiceImpl">

        <!--
         ref="studentDao"  通过ref  引用id studentDao的bean 进行装配
         -->
        <property name="studentDao" ref="studentDao">

        </property>

    </bean>

</beans>

测试

public class XmlTest {

    public static void main(String[] args) {


        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("xml/settter_bean.xml");



        // 按照类型 去获取 Bean  如果容器中只有一个 bean 可以,如果有多个同类型的bean
        // 则报错 available: expected single matching bean but found 2: student1,student2
        // 容器找到了 两个bean ,但是不确定你需要那一个bean
        // 需要你传更确且  name  id  来查找
        Student student1 = (Student) applicationContext.getBean("student1");
        System.out.println("student1:"+student1);


        Student student2 = (Student) applicationContext.getBean("student2");
        System.out.println("student2:"+student2);


        // 获取类型  StudentService.class 实例 bean
        StudentService studentService = applicationContext.getBean(StudentService.class);

        Student student3 =   studentService.findStudentById(2000);
        System.out.println("student3:"+student3);

    }
}

二、基于注解的装配

基于XML的装配可能会导致XML配置文件过于臃肿,给后续的维护和升级带来一定的困难。为此,Spring提供了对Annotation(注解)技术的全面支持。

注入的注解 设置值

@Autowired
用于对Bean的属性变量、属性的setter方法及构造方法进行标注,配合对应的注解处理器完成Bean的自动配置工作。
@Qualifier:与@Autowired注解配合使用,

会将默认的按Bean类型装配修改为按Bean的实例名称装配,

Bean的实例名称由@Qualifier注解的参数指定。

     @Autowired  
		// 去容器中 根据对应类型 查找对应bean ,
		//并设置到当前 属性中  
		//如果容器有 多个类型的bean则报错
     @Qualifier("studentDao1")  
		//  @Qualifier 与@Autowired 配合 ,
		//当根据类型找到多个时 
		//使用  @Qualifier 按照id  或者name 查找为一个bean


@Resource:其作用与Autowired一样。@Resource中有两个重要属性:name和type。Spring将name属性解析为Bean实例名称,type属性解析为Bean实例类型。

//  @Resource 
//首先按照 id 为属性名studentDao 去容器中找到对应的bean
// 2.如果找不到 在按照类型去查找 如果找到多个 报错
        @Resource(name = "studentDao1")  // 如果传递 name  则按照 name 为studentDao1 去容器中查找 id 或者name 相同的bean


生成bean的注解

这四个注解都是都一个作用生成bean,@Component是其他三个的父类

@Component

@Repository 指明当前实例 是dao 层的实例

@Service 指明当前实例是service 层的实例

@Controller 指明当前实例是控制 层的实例 但是springmvc 中控制层只能用 @Controller

半自动注解装配

只能进行注入,使注入的注解生效,bean的生成还需要在xml进行配置

实现是 context:annotation-config</context:annotation-config>

1.首先在容器中声明bean

2.使用对应注入的注解 注入bean

3.是注入的注解生效

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">




    <!--
        作用就是让 注入的注解生效
    -->
    <context:annotation-config></context:annotation-config>



    <!--1. 声明 bean-->
    <bean id="studentDao" class="com.qfedu.dao.impl.IStudentDaoImpl"></bean>


    <bean id="studentService" class="com.qfedu.service.StudentServiceImpl">

    </bean>



</beans>

    public class StudentServiceImpl implements StudentService {
    
        // 使用注入的注解 注入bean
        @Autowired  // 去容器中 根据对应类型 查找对应bean ,并设置到当前 属性中
        private IStudentDao studentDao ;
    
        public IStudentDao getStudentDao() {
            return studentDao;
        }
    
        public void setStudentDao(IStudentDao studentDao) {
            this.studentDao = studentDao;
        }
    
        public Student findStudentById(int id) {
            return studentDao.findStudentById(id);
        }
    }


  <!--
        作用就是让 注入的注解生效
    -->
    <context:annotation-config></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/beans http://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></context:annotation-config>



    <!--1. 声明 bean-->
    <bean id="studentDao1" class="com.qfedu.dao.impl.IStudentDaoImpl"></bean>
    <bean id="studentDao2" class="com.qfedu.dao.impl.IStudentDaoImpl"></bean>


    <bean id="studentService" class="com.qfedu.service.StudentServiceImpl">

    </bean>



</beans>

public class StudentServiceImpl implements StudentService {

        // 使用注入的注解 注入bean
//        @Autowired  
    // 去容器中 根据对应类型 查找对应bean ,并设置到当前 属性中  
    //如果容器有 多个类型的bean则报错
//     @Qualifier("studentDao1")  
    //  @Qualifier 与@Autowired 配合 ,
    //当根据类型找到多个时 使用  @Qualifier 按照id  或者name 查找为一个bean

//        @Resource // 首先按照 id 为属性名studentDao 去容器中找到对应的bean 2.如果找不到 在按照类型去查找 如果找到多个 报错
        @Resource(name = "studentDao1")  // 如果传递 name  则按照 name 为studentDao1 去容器中查找 id 或者name 相同的bean
        private IStudentDao studentDao ;

        public IStudentDao getStudentDao() {
            return studentDao;
        }

        public void setStudentDao(IStudentDao studentDao) {
            this.studentDao = studentDao;
        }

        public Student findStudentById(int id) {
            return studentDao.findStudentById(id);
        }
    }


测试

/**
 * 半自动 注解 注入装配
 */
public class HalfAutoTest {

    public static void main(String[] args) {


        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("annotation/half_auto_bean.xml");


        // 获取类型  StudentService.class 实例 bean
        StudentService studentService = applicationContext.getBean(StudentService.class);

        Student student3 =   studentService.findStudentById(2000);
        System.out.println("student3:"+student3);


    }
}


三、自动注解 context:component-scan

自动注解就是 通过注解自动的生成bean 并经行装配

官方:扫描 当前包下面的注解@Component @Controller @Service @Repository,生成实例,并装配 @Autowired @Resource

实现:在xml 声明 context:component-scan 使对应包下的 注入的注解(@Autowired @Qualifie @Resource )生成bean的注解(@Component@Repository @Service @Controller)生效

实现

1.开启自动注解

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">



    <!--
        开启 自动注解功能 使 注入的注解(@Autowired @Qualifie @Resource )生成bean的注解(@Component@Repository @Service @Controller)生效
    -->
     <context:component-scan base-package="com.qfedu"></context:component-scan>


</beans>

2.标记需要 生成 bean 和主要注入的属性

dao

//@Component("studentDao1")  // 将IStudentDaoImpl 生成实例 并加入到容器中 为生成的bean 制定id studentDao1
@Repository  // 标记当前类是dao层
public class IStudentDaoImpl implements IStudentDao {
    public Student findStudentById(int id) {

        Student student = new Student();
        student.setId(id);
        student.setName("xxxx");
        return student;
    }
}


service

//@Component  // 将当前类 生成对象并加入到 容器
@Service  // 继承 @Component 功能
public class StudentServiceImpl implements StudentService {

        // 使用注入的注解 注入bean
//        @Autowired  // 去容器中 根据对应类型 查找对应bean ,并设置到当前 属性中  //如果容器有 多个类型的bean则报错
//        @Qualifier("studentDao1")  //  @Qualifier 与@Autowired 配合 ,当根据类型找到多个时 使用  @Qualifier 按照id  或者name 查找为一个bean

//        @Resource // 首先按照 id 为属性名studentDao 去容器中找到对应的bean 2.如果找不到 在按照类型去查找 如果找到多个 报错
        @Resource(name = "studentDao1")  // 如果传递 name  则按照 name 为studentDao1 去容器中查找 id 或者name 相同的bean
        private IStudentDao studentDao ;

        public IStudentDao getStudentDao() {
            return studentDao;
        }

        public void setStudentDao(IStudentDao studentDao) {
            this.studentDao = studentDao;
        }

        public Student findStudentById(int id) {
            return studentDao.findStudentById(id);
        }
    }


测试

    public static void main(String[] args) {


        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("annotation/auto_bean.xml");




        // 获取类型  StudentService.class 实例 bean
        StudentService studentService = applicationContext.getBean(StudentService.class);

        Student student3 =   studentService.findStudentById(2000);
        System.out.println("student3:"+student3);
    }

基于xml 自动装配

所谓自动装配,就是将一个Bean自动的注入到到其他Bean的Property中。 Spring的元素中包含一个autowire属性,我们可以通过设置autowire的属性值来自动装配Bean。autowire属性有5个值,

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">



    <bean id="studentDao" class="com.qfedu.dao.impl.IStudentDaoImpl"></bean>


    <bean id="studentDao2" class="com.qfedu.dao.impl.IStudentDaoImpl"></bean>

    <!--
        基于 xml 自动装配
          autowire="byType" StudentServiceImpl 中属性 需要那些bean 就去根据类型去容器查找对应bean
          autowire="byName"  StudentServiceImpl 根据属性中对应属性名 作为id 去查找 ,如果找不到就不设置对应的属性
          autowire="constructor" 1.首先根据类型去类型 去查找,如果找到一个就设置对应bean 
                                   2.如果找到两个 则根据参数变量名去查找   根据构造器中对应 参数名作为id 去查找 查找不到就传null 
      -->
    <bean id="studentService" class="com.qfedu.service.StudentServiceImpl"  autowire="constructor">
    </bean>

</beans>

测试

/**
 * xml 自动装配
 */
public class XMLAuto {

    public static void main(String[] args) {

        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("xml/xml_auto_bean.xml");



        // 获取类型  StudentService.class 实例 bean
        StudentService studentService = applicationContext.getBean(StudentService.class);

        Student student3 =   studentService.findStudentById(2000);
        System.out.println("student3:"+student3);

    }
}

4.代理模式

什么是代理模式?

客户端不直接和目标对象发生交互/不直接调用目标对象,而是通过代理对象,让代理对象调用目标对象的设计模式

在这里插入图片描述

为什么要用代理模式?

1.当客户端不能直接访问目标对象时,需要通过代理进行间接访问

2.在不改变目标对象的代码情况下,通过代理对目标对象的功能进行增强

增加日志,鉴权登陆,权限控制,事务控制

代理模式分类

静态代理

静态代理,代理类只能代理某一特定的目标对象,并且对目标对象进行增强

例子。。。。。

动态代理

动态代理,代理对象可以代理很多类型的目标对象,并且对目标对象进行增强

动态代理的实现有两种

jdk 基于接口的动态代理

基于java jdk实现 只能代理 实现接口的目标对象,如果没有接口 报错

1.搞清楚Proxy.newProxyInstance 三个参数的意思
2.返回的代理对象是 目标对象实现的接口
3.当代理对象调用对应的接口方法时 会回调传递第三个参数 InvocationHandler 对象内的 invoke 方法,
  invoke 方法 作用是让目标对象执行响应的方法

        // 12306  目标对象
        final TicketBy12306Impl t12306 = new TicketBy12306Impl();


        // 创建一个代理对象
        // ClassLoader loader, 类加载器
        //  Class<?>[] interfaces,  目标对象 实现的接口  代理目标对象必须 实现接口
		//      t12306.getClass().getInterfaces()  获取目标对象实现的接口
        //  InvocationHandler h  当代理对象执行 接口的方法时 会回调InvocationHandler 的 invoke
        
        Ticket proxyTicket = (Ticket) Proxy.newProxyInstance(t12306.getClass().getClassLoader(), t12306.getClass().getInterfaces(), new InvocationHandler() {
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                System.out.println("代理对象开始调用 目标对象");

                // 让目标对象执行方法  并且获取返回结果
                Object result =   method.invoke(t12306,args);


                System.out.println("代理对象结束调用 目标对象");

                return result;
            }
        });

实例

1.创建JdkProxy

/**
 * 专门用于 产生 JDK代理对象
 */
public class JdkProxy implements InvocationHandler{

    // 目标对象
    private Object target;

    public Object createProxy(final Object target){

        this.target = target;

        // 创建 代理对象
        // this  当前对象实现 InvocationHandler
       return    Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),this);
    }


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

        System.out.println("代理对象开始调用 目标对象");

        // 让目标对象执行方法  并且获取返回结果
        Object result =   method.invoke(target,args);


        System.out.println("代理对象结束调用 目标对象");

        return result;
    }
}


2.测试

/**
 *  JdkProxy 可以产生多个代理对象  ,但是代理对象必须实现 接口  如果目标对象 没有实现接口 则报错
 */
public class JdkProxyTest2 {
    public static void main(String[] args) {


        // 12306  目标对象
        final Ticket t12306 = new TicketBy12306Impl();


        JdkProxy jdkProxy = new JdkProxy();

        // 创建 12306 代理对象黄牛
        Ticket huangNiuticket = (Ticket) jdkProxy.createProxy(t12306);

        String str = huangNiuticket.bubTicket();
        System.out.println("str:"+str);

        System.out.println("***********************************");
        // 目标对象
        Subject realSubject = new RealSubject();

        // 创建Subject 的代理对象
        Subject proxySubject = (Subject) jdkProxy.createProxy(realSubject);

        proxySubject.action();
    }
}


cglib 基于类的动态代理
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值