程序的耦合和解耦。

1、问题引入。

在使用jdbc和数据库交互时。注册驱动:DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());
如果把mysql的依赖(jar包)删掉,那么程序在编译期就会出现错误。也就是说当前类,依赖于Driver类。

2、程序的耦合。

耦合:简单来说,就是程序间的依赖关系。包括:类之间的依赖、方法之间的依赖。

解耦:降低程序间的依赖关系。

实际开发中应做到:编译期不依赖,运行时才依赖。

之前注册驱动时,一直用的是  Class.forName("com.mysql.cj.jdbc.Driver")。它依赖的只是一个字符串。

所以,

解耦的思路:

  * 第一步:使用反射来创建对象,而 避免使用new关键字。

    问题:这样的话,字符串写死了,如果以后用其他数据库驱动,需要改源码。

  * 第二部:通过读取配置文件来获取要创建的对象全类名。

3、另一个问题。

通过分析,在之前的三层架构中,各个层之间的调用也有很大的耦合问题。

解决方案:工厂模式解耦。

  创建一个 创建Bean对象的工厂。

  Bean:代表可重用组件的含义。

  JavaBean:用Java编写的可重用组件。JavaBean > 实体类。

  第一:需要一个配置文件来配置service和dao。配置的内容:唯一标识=全类名。

  第二:通过读取配置文件的内容,反射创建对象。

public class BeanFactory {
private static Properties properties;
static {
properties=new Properties();
InputStream is=BeanFactory.class.getClassLoader().getResourceAsStream("beanfactory.properties");
try {
properties.load(is);
} catch (IOException e) {
e.printStackTrace();
}
}
public static Object getBean(String beanName) {
Object bean=null;
String beanPath=properties.getProperty(beanName);
try {
bean=Class.forName(beanPath).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return bean;
} }

由于这句代码的存在 bean=Class.forName(beanPath).newInstance();  导致每次用的时候都会创建一个新的对象。

改进方法:将对象先创建完,存入集合中,用的时候直接在集合中拿。、

改进后的工厂模式:

public class BeanFactory {
private static Properties properties;
private static Map<String,Object> beans;
static {
properties=new Properties();
InputStream is=BeanFactory.class.getClassLoader().getResourceAsStream("beanfactory.properties");
try {
properties.load(is);
beans =new HashMap<String, Object>();
Enumeration keys = properties.keys();
while (keys.hasMoreElements()){
String key=keys.nextElement().toString();
String beanPath=properties.get(key).toString();
Object value=Class.forName(beanPath).newInstance();
beans.put(key,value);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static Object getBean(String beanName) {
return beans.get(beanName);
} }

private AcountDao dao=new AcountDaoImp();

private AcountDao dao=(AcountDaoImp)BeanFactory.getBean("AcountDao");

这两种获取对象的形式上,第一种,应用程序直接依赖于资源。而第二种,利用工厂消除了应用程序和资源的直接依赖关系。

第二种方法的思想,就是IOC。

为什么叫控制反转,不叫降低依赖?

  因为,对于应用程序来说,用第一种方式创建对象时,有自己的独立控制权,想要谁就要谁,而第二种方式,应用程序失去了控制器,把控制权交给了工厂和配置文件。这种控制权发生的转移,就是控制反转。

Spring的IOC和DI。

控制反转(Inversion of Control,IOC)把创建对象的权力交给框架,是框架的重要特征。

IOC的作用:削减计算机程序的耦合。

Spring基于xml的IOC的环境搭建:

  1、导入依赖。

  2、配置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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="AcountDao" class="AcountDao.AcountDaoImp"></bean>
<bean id="AcountService" class="AcountService.AcountServiceImp"></bean>
</beans>

  3、主程序。

 public static void main(String[] args) {
//1、获取核心容器对象
ApplicationContext ac=new ClassPathXmlApplicationContext("bean.xml");
//2、根据id获取Bean对象
AcountService acountService=(AcountService)ac.getBean("AcountService");
AcountDao acountDao=ac.getBean("AcountDao",AcountDao.class);
System.out.println(acountService);
System.out.println(acountDao); }

ApplicationContext 的三个常用实现类。

  1、ClassPathXmlApplicationContext:它可以加载类路径下的配置文件,要求配置文件必须在类路径下。

  2、FileSystemXmlApplicationContext:它可以加载任意路径下的配置文件。

  3、AnnotationConfigApplicationContext:用于注解创建容器。

核心容器的两个接口。

  1、ApplicationContext:它在构建核心容器时,创建对象采用的策略是立即加载的方式,也就是说,只要一读取完配置文件,马上就创建对象。

  2、BeanFactory:它采用延迟加载的方式,什么时候需要,什么时候创建对象。

Spring对Bean的管理细节。

  1、创建bean 的三种方式。

    * 使用默认构造函数创建:在spring配置文件中使用bean标签,配以id和class属性,且没有其他属性和标签时,采用的就是默认构造函数创建bean对象,此时如果类中没有默认构造函数,则无法创建。

    * 使用普通工厂的方法创建对象(使用某个类的方法创建其他类对象):在bean标签中使用 factory-bean和factory-method 属性指定类和方法。

    * 使用工厂的静态方法创建对象(使用某个类的静态方法创建对象):使用class和factory-method属性。

  2、Bean的作用范围。

    bean标签的scope属性取值:

      * singleton:单例的(默认值) 常用

      * prototype:多例的。常用

      * request:作用于web应用的请求范围。

      * session:作用于web应用的会话范围。

      * global-session:作用于集群环境的会话范围。

  3、Bean对象的生命周期。

    * 单例对象。

      出生:当容器创建时对象出生。

      活着:只要容器存在,对象就一直存在。

      死亡:容器销毁,对象销毁。

      总结:单例对象的生命周期和容器相同。

    * 多例对象。

      出生:要使用对象时创建。

      活着:对象 只要在使用过程中就一直活着。

      死亡:对象长时间不用,且没有被引用时,由jvm回收。

Spring中的依赖注入。

IOC的作用:降低程序间的依赖关系(耦合)

依赖关系的管理:以后都交给spring来维护。

在当前类需要用到其他类的对象时,由spring为我们提供,我们只需在配置文件中说明。

依赖关系的维护就称之为依赖注入。

依赖注入:

  1、能注入的数据,有三类:

    *基本类型和String

    *其他bean类型(在配置文件中或注解配置过的bean)

    *复杂类型/集合类型

  2、注入的方式,有三种:

    第一种:使用构造函数提供

      使用的标签:constructor-arg

      标签的位置:bean里

      标签中的属性:

        * type:指定注入数据的类型,也是构造函数中参数的类型。

        * index:要注入的数据在构造函数中的位置。

        * name:构造函数中指定参数。

        * value:用于提供基本类型和String类型的数据。

        * ref:用于指定其他的bean类型数据。

<bean id="AcountService" class="AcountService.AcountServiceImp">
<constructor-arg name="name" value="rt"></constructor-arg>
<constructor-arg name="age" value="21"></constructor-arg>
<constructor-arg name="birthday" ref="birthday"></constructor-arg>
</bean>
<bean id="birthday" class="java.util.Date"></bean>

      优势:获取bean对象时,注入数据是必须的操作。

      弊端:改变了bean对象的实例化方式,如果创建对象时用不到这些数据,也必须提供。

    第二种:使用set方法提供    更常用

      涉及的标签:property

      出现的位置:bean里

      标签的属性:

        * name:指定注入时所调用的set方法名称。

        * value:用于提供基本类型和String类型的数据。

        * ref:用于指定其他的bean类型数据。

      优势:创建对象时没有明确的限制,可以直接使用默认的构造函数。

      弊端:如果某个成员必须有值,则获取对象时有可能set方法没有执行。

      复杂类型/集合类型的注入:

        *用于给list结构的集合注入的标签:list   arry  set

        *用于给map结构的集合注入的标签:map  props

    第三种:使用注解提供

      用于创建对象的注解: 它们的功能和<bean>标签实现的功能一样

        1、@Component:把当前类对象存入spring容器中。

        属性:value:用于指定bean的id。默认是当前类名,且首字母小写。

        2、@Controller:一般用于表现层

        3、@Service:一般用在业务层

        4、@Repository:一般用在持久层

        以上三个注解的作用和@Componet一样,是Spring为我们提供的明确三层使用的注解,

        使我们的三层对象更加清晰。

        需要的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/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"> <!--告知spring在创建容器时要扫描的包,配置所需的标签不是在beans的约束中,而是
一个名称为context名称空间和约束中-->
<context:component-scan base-package="AcountService"></context:component-scan> </beans>

      用于注入数据的注解:它们的作用和bean中的<property>标签的作用一样

        1、@Autowired:

          * 作用:自动按类型注入。

              * 只要容器中有唯一的一个bean对象类型和要注入的变量类型匹配,就可以成功注入。

              * 如果ioc容器中没有任何bean的类型和要注入的变量类型匹配,则报错。

              * 如果ioc容器中有多个匹配的类型时,在将变量名作为bean的id,继续查找匹配项。

          * 出现位置:变量上,或者方法上。

        2、@Qualifier:

          * 作用:在按照类型注入的基础上再按照名称注入。它在给类成员注入时不能单独使用(需要AotoWired)。但是在给方法参数注入时可以。

          * 属性:value:用于指定注入bean的id。

        3、@Resource:

          * 作用:直接按照bean的id注入,可以单独使用。

          * 属性:name:bean的id。

        4、@Value:

          * 作用:用于注入基本类型和String类型的数据。

          * 属性:value:用于指定数据的值。可以使用spring的SpEL表达式。${表达式}

      用于改变作用范围的注解:它们的作用和bean中的scope属性作用一样

        1、@Scope:

          * 作用:指定bean的作用范围。

          * 属性:value:指定范围的取值:singleleton   prototype

      和生命周期相关的注解:它们的作用和bean中的init-method  和 destroy-method  属性的作用一样

        1、@PreDestroy

          * 作用:用于指定销毁方法

        2、@PostConstruct

          * 作用:用于指定初始化方法

Spring中的新注解:

虽然上面的描述中已经使用了注解来配置,但是任然需要xml文件。

解决方案:创建一个配置类。

  1、@Configuration

    * 作用:指定当前类是一个配置类。

  2、@ComponetScan

    * 作用:指定spring在创建容器时需要扫描的包

    * 属性:value:它和basePackeages的作用一样,都用于指定创建容器时需要扫描的包,相当于xml的:<context:component-scan base-package="AcountService"></context:component-scan>

  3、@Bean

    * 作用:将当前方法的返回值作为bean对象存入ioc容器。

    * 属性:name:指定bean 的id,默认是方法名称。

    * 细节:使用注解配置方法时,如果方法有参数,spring会在容器中查找有没有可用的bean对象,查找方式和Aoutowired一样。

  4、@Import

    * 作用:用于导入其他配置类。

    * 属性:value:指定其他配置类的字节码。、

       使用Import注解的类是父配置类,导入的是子配置类。

  5、@PropertySource

    * 作用:用于指定properties文件的位置。

    * 属性:value:文件的名称和路径。 关键字:classpath:表示类路径下。

Spring整合Junit的配置。

  1、导入jar坐标。

  2、使用Junit提供的一个注解把原有的main方法替换成spring提供的。

    @Runwith(SpringJUnit4ClassRunner.clsss)

  3、告知spring的运行器,spring和ioc创建是基于xml还是基于注解,且说明位置。

    @ContextConfiguration

      location:指定xml文件的位置,加上classpath,表示在类路径下。

      classes:指定注解类所在位置。

  当使用spring5.x时,要求junit必须是4.12及以上。

AOP:

动态代理:

  特点:字节码随用随创建,随用随加载.

  作用:不修改源码的基础上对方法增强.

  分类:基于接口的动态代理   基于子类的动态代理.

  基于接口的动态代理:

    1.涉及的类:Proxy

    2.提供者:JDK

    3.如何创建代理对象:newProxyInstance方法.

    4.创建代理对象的要求:被代理类最少实现一个接口.

    5.newProxyInstance方法的参数:

      * ClassLoader:类加载器. 用于加载代理对象的字节码,和被代理对象使用相同的类加载器. 固定写法.

      * Class[] :字节码数组. 用于让代理对象和被代理对象有相同的方法. 固定写法.

      * InvocationHandler: 用于提供增强的代码. 它是让我们写如何代理. 一般都是写一个该接口的实现类,通常是匿名内部类,但不是必须的.

    6.invoke方法的作用: 执行被代理对象的任何接口方法都经过改方法(拦截作用)

    7.invoke方法的参数:

      * proxy:代理对象的引用.

      * method: 当前执行的方法.

      * args :当前执行方法所需的参数.

      * 返回值: 和被代理对象方法有相同的返回值.

问题引入:

  在转账案例中,分析可知,应该使用ThreadLocal对象把Connection和当前线程绑定,从而使一个线程只能有一个能控制事务的对象。

AOP概述:

AOP:Aspect Oriented Programming 。面向切面编程。

作用:在程序运行期间,不修改源码对已有的方法进行增强。

优势:减少重复代码,提高开发效率,维护方便。

实现方式:动态代理。

Spring中的AOP:spring中的AOP就是通过配置的方式,实现AOP功能 。

  1、引入依赖。

  2、开启基于注解的AOP功能<aop:aspectj-autoproxy>

  3、写切面类(重复的模块),并用存入容器,@Component ,以及声明为切面类 @Aspect

  4、申明切面类的各种通知(方法)是什么时候执行(@before....),然后声明在切入哪个方法(切入点表达式):@before(“execution(修饰符 返回值 方法全类名)”)。可以在通知方法中声明类型为 JoinPoint的参数,用来访问被代理方法的参数。

AOP中的细节:

  1、有接口时,使用的对象并非原对象,而是代理对象,它们之间唯一的关系是实现了同一个接口,所以要用接口类型来接收。没有接口时,用的是cglib创建的代理对象,可以用原对象来接收。

  2、切入点表达式:

    i:可以使用通配符:*  :1、匹配任意字符 Mymethod* :以Mymethod开头的所有方法。  2、匹配任意一个参数(int ,*) 一个int  一个任意。

             .. :1、匹配任意个参数(..)  2、匹配任意多层路径  com.sicau..mymethod(..)

  3、切入方法执行顺序:正常:@before @after(finally里面)  @afterreturnning(方法返回后) 异常:@before @after(finally里面) @afterthrowing

  4、可以使用JoingPoint  获取当前执行方法对象。

  5、通知方法的格式要求是不严谨的,唯一要注意的是,参数不能乱写,因为最终方法是由spring调用,它要知道具体参数是什么,比如你要获得异常,需要在注解上申明:throwing=变量名。

  6、抽取可重用的切入点表达式:随便申明一个void 方法 ,方法加@PointCut(表达式),引用:直接用方法名引用。

  7、环绕通知,通知上加@Around,它就是一个动态代理,ProceedingJoinPoint 对象.proceed ,就是相当于invoke方法,可以在方法周围写通知。

  8、环绕通知在普通通知之前执行,因为普通通知是在proceed方法执行后才能执行的。

  9、多个切面同时作用时,可以使用@Order ,数字越小,越优先执行,执行过程相当于嵌套过程。

Spring中的事务:

  1、事务回滚:默认发生运行时异常会回滚,但但发生编译时异常不会回滚。@Translational 中的属性:norollbackfor={class} 哪些异常可以不回滚。rollbackfor={class} 哪些异常要回滚。

  2、事务传播行为:事务里有其他事务时,  propagation=Propagation.Require    使用当前事务    propagation=Propagation.Require_new  使用新事务。

      使用require时,事务的属性都是继承大事务的,自己设的属性无效。

Spring入门。的更多相关文章

  1. Spring入门学习(一)

    SpringMVC基础平台补充(2016.03.03) 如果想要开发SpringMVC,那么前期依次安装好:JDK(jdk-8u74-windows-x64,安装后配置环境变量JAVA_HOME和CL ...

  2. Spring入门(10)-Spring JDBC

    Spring入门(10)-Spring JDBC 0. 目录 JdbcTemplate介绍 JdbcTemplate常见方法 代码示例 参考资料 1. JdbcTemplate介绍 JdbcTempl ...

  3. Spring入门(9)-AOP初探

    Spring入门(9)-AOP初探 0. 目录 什么是面向切面编程 AOP常见术语 AOP实例 参考资料 1. 什么是面向切面编程 Aspect Oriented Programming(AOP),即 ...

  4. Spring入门(8)-基于Java配置而不是XML

    Spring入门(8)-基于Java配置而不是XML 本文介绍如何应用Java配置而不是通过XML配置Spring. 0. 目录 声明一个简单Bean 声明一个复杂Bean 1. 声明一个简单Bean ...

  5. Spring入门(7)-自动检测Bean

    Spring入门(7)-自动检测Bean 本文介绍如何自动检测Bean. 0. 目录 使用component-scan自动扫描 为自动检测标注Bean 1. 使用component-scan自动扫描 ...

  6. Spring入门(6)-使用注解装配

    Spring入门(6)-使用注解装配 本文介绍如何使用注解装配. 0. 目录 使用Autowired 可选的自动装配 使用Qualifier选择 1. 使用Autowired package com. ...

  7. Spring入门(5)-自动装配Bean属性

    Spring入门(5)-自动装配Bean属性 本文介绍如何装配Bean属性. 0. 目录 ByName ByType constructor 默认自动装配 混合使用自动装配和显示装配 1. ByNam ...

  8. Spring入门(4)-注入Bean属性

    Spring入门(4)-注入Bean属性 本文介绍如何注入Bean属性,包括简单属性.引用.内部Bean.注入集合等. 0. 目录 注入简单值 注入引用 注入内部Bean 装配集合 装配空值 使用命名 ...

  9. Spring入门(3)-Spring命名空间与Bean作用域

    Spring入门(3)-Spring命名空间与Bean作用域 这篇文章主要介绍Spring的命名空间和Bean作用域 0. 目录 Spring命名空间 Bean作用域 1. Spring命名空间 在前 ...

  10. Spring入门(2)-通过构造器注入Bean

    Spring入门(2)-通过构造器注入Bean 前一篇文章将了最基本的spring例子,这篇文章中,介绍一下带有参数的构造函数和通过构造器注入对象引用. 0. 目录 带有参数的构造函数 通过构造器注入 ...

随机推荐

  1. Git命令行操作(三)

    1. 本地库初始化 进入指定目录,如:D:\gitSpace\OA 右键-->Git Bash Here,执行命令: git init 效果如下: #查看.git目录 ls -la # 进入.g ...

  2. shell的变量以及常见符号

    shell的变量以及常见符号 常见变量 不同于其它语言需要先声明变量,shell的变量直接使用 eg:      a=15 调用变量的话 $a 或者 ${a} $? #判断上一条命令执行的是否成功 0 ...

  3. python 环境搭建 python-3.4.4

    第一步:下载和安装python-3.4.4amd.msi 可以去官方网站下载,也可以从网盘下载: 链接:https://pan.baidu.com/s/1dZ9ibgigKPdPUJgykLA_jg ...

  4. Today's missions

    A software for recording events and tasks. You can add, delete and edit tasks anytime, anywhere, eas ...

  5. Python搭建HTTP服务

    我们平时可能会需要HTTP服务,本机搭建一个服务器来完成有些过于繁琐,这时就可以用python帮我们搭建一个HTTP服务器,省时高效. python 2.x 输入命令:python -m Simple ...

  6. tornado模板的使用

    一. 配置模板路径 settings中使用template_path来指定模板的路径, 实例化服务对象时加载进去即可. 二. 模板的使用 1. 使用self.render()方法可返回指定的html页 ...

  7. [题解向] 正睿Round435

    10.14 Link 唔,这一场打得不好.获得了\(\rm 75pts/300pts\)的得分,但是居然可以获得\(\rm 27/69\)的名次,也不至于不满意--毕竟是真不会233 \(\rm T1 ...

  8. [LeetCode] 223. Rectangle Area 矩形面积

    Find the total area covered by two rectilinearrectangles in a 2D plane. Each rectangle is defined by ...

  9. OAuth2、OpenID、SMAL 对比

    对比点 OAuth2.0 OpenID SMAL2 票据格式 JSON or SAML2 JSON XML 支持授权 Yes Yes Yes 支持认证 “伪认证” Yes Yes 创建年份 2005 ...

  10. netcore与ef资料收集

    http://www.cnblogs.com/cgzl/p/7661805.html https://www.cnblogs.com/cgzl/p/7675485.html https://www.c ...