一、Mybatis中拦截器的支持
过滤器和拦截器作用都差不太多 都是在某一个目标操作之前 会执行一些列内容
过滤器依赖于Tomcat容器 拦截器是可以在javaSE项目中使用 不依赖于Tomcat容器
●创建分页参数工具类
创建com.bjsxt.interceptor.MyPageHelper。
MyPageHelper类名称自定义的。作用为了设置分页的条件。没有这个类,实现的分页必须写成固定值。全局变量设置为protected表示同包能方法,此类会和插件类放在一个包下。
startPage提供的静态方法,方便以后设置分页的条件。
●创建插件实现类
新建com.bjsxt.interceptor.MyPageHelperInterceptor。
注意下类上面的注解。
@Intercepts 表示当前是一个拦截器。
@Signature表示签名。
type:拦截器主要拦截的类型,可以是四大核心接口。
method:拦截type中的哪个方法
args:method对应方法的参数。这个很重要,因为Java支持方法重载,不设置参数可能无法精确到具体的方法。
●配置插件 java
在MyBatis全局配置文件中配置插件,如果不配置,插件是无法被识别的。
需要把<plugins>标签配置在<environment>标签的上面。这点是DTD的要求。
里面的属性对于当前演示没有实际作用,单纯为了演示如果传递属性。
●查看控制台结果
通过控制台效果图可以看出来
1.能够成功获取配置插件时的属性值
2.在自己定义的SQL后面拼接上了1imit关键字
●使用PageHelper分页插件步骤
•导入依赖
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.3.0</version>
</dependency>
•在mybatis.xml中进行配置
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
●在代码中使用即可
查询之前 添加:PageHelper.startPage(2,2);
查询之后可以在PageInfo<Clazz> info=new PageInfo<>(list);对象中获得分页相关信息
二、Spring框架
Spring Framework其主要目的是为了简化项目开发。
主要是为了不使用EJB下依然能够构建高质量Java EE项目。
●Spring各个模块
•Test
对应spring-test.jar. Spring提供的测试工具,可以整合JUnit测试,简化测试环节.
•Core Container
Spring的核心组件,包含了Spring框架最基本的支撑.
Beans,对应spring-beans.jar.Spring进行对象管理时依赖的jar包.
Core,对应spring-core.jar,Spring核心jar包.
Context,对应spring-context.jar, Spring容器上下文对象。
SpEL,对应spring-expression.jar,Spring表达式语言.
•AOP
面向切面编程,对应spring-aop.jar.
•Aspects
Aspect的具体实现,面向切面编程的另一种实现。对应spring-aspects.jar
•Instrumentation
服务器代理接口的具体实现。对应spring-instrument.jar
•Messaging
集成messaging api和消息协议提供支持。对应spring-messaging.jar
•Data Access/Integration
Spring对数据访问层的封装
JDBC,对应spring-jdbc.jar.Spring对jdbc的封装,当需要使用spring连接数据库时使用.spring-jdbc.jar需要依赖spring-tx.jar.Transactions,对应spring-tx.jar.事务管理
ORM,对应spring-orm.jar.spring整合第三方orm框架需要使用的jar包,例如Hibernate框架.
•Web
Spring对javax下的接口或类做的扩展功能.
spring-web.jar,对Servlet, filter,Listener等做的增强
spring-webmvc.jar,实际上就是SpringMVC框架.需要依赖spring环境和spring-web.jar
●SpringDI 依赖注入的方式
•构造注入
name:需要和对应构造方法中形参名称保持一致
value:赋予属性的值
index:属性对应的下标
type:属性对应的类型
如果我们注入的值是常用类型(例如基本数据类型、对应包装类、String)使用value如果给某些对象注入值的时候 使用ref
•SET方法
name:和对应类中SET方法名称保持一致
三、Spring loC/DI
loC(Inversion of Control)中文名称:控制反转。也被称为DI(dependency injection)依赖注入。属于同一件事情的两个名称。
loC/DI是指一个过程:对象的创建仅仅通过Spring容器负责,Spring容器可以通过对象的构造方法或工厂方法进行实例化对象。
在创建对象过程中,如果对象需要依赖其他对象,也可以直接在Spring容器中注入到当前对象。
整个过程中对象本身在容器中控制自己的实例化(所以叫做控制反转),通过构造方法或setter方法把依赖对象注入到自己(所以又叫做依赖注入)
●容器(Container):放置所管理对象的对象。其本质是在容器对象里面有一个全局Map对象,map对象中放置所有被管理的对象。Spring中容器是指ApplicationContext接口及子接口或实现类。
beans:容器中所有被管理的对象称为beans。如果单说其中一个对象可称为bean。
●loC/DI的好处
Spring loC/DI使用后可以管理项目中相关对象,让对象管理的事情和业务分离(解耦)。同时也不管理对象的依赖关系,所有的依赖关系交给Spring容器进行管理。
●1oC/DI具体应用场景
1oC/DI主要作用就是管理对象的实例化和对象之间依赖关系。项目中以前需要自己实例化的层对象、需要自己实例化框架或工具包的入口类都可以交给Spring容器进行管理。
•层对象:PeopleMapper接口代理对象、PeopleDaolmpl、PeopleServicelmpl
•框架入口类:SqlSessionFactory等
下图中对应普通类PeopleMapper、PeopleServicelmpl这些不同层中普通都可以交给Spring容器进行管理。放入到容器中的对象可以相互直接依赖。但是Servlet只能被Tomcat管理(由Tomcat帮助实例化创建的),所以Spring容器是无法管理Servlet的。但是Servlet可以从Spring容器中取出对象。
四、第一个Spring项目
Spring框架不依赖于Servlet容器(Tomcat),所以普通Java项目就可以使用Spring框架。
Spring框架提供了XML、注解、Java Config三种方式进行使用。首先我们从XML方式开始学习。
●创建项目,并添加依赖
创建普通Maven项目,并命名为spring1.
在项目的pom.xml中添加Spring项目的最基本依赖。
Spring项目想要运行起来必须包含:
• spring-context.jar。 spring上下文依赖,它依赖了下面的四个jar。
•spring-core.jar。Spring 核心jar包。它依赖了spring-jcl.jar
•spring-aop.jar。SpringAOP基本支持。
• spring-expression.jar。Spring的表达式语言支持。
•spring-beans.jar。Spring容器的bean管理。
•spring-jcl.jar。Spring 4版本时是common-logging.jar。从5开始Spring自己对日志进行了封装。
所以在Maven中想要使用Spring框架只需要在项目中导入spring-context就可以了,其他的jar包根据Maven依赖传递性都可以导入进来
●随意创建一个类
在项目下创建一个类作为测试Spring loC/DI功能的类。
五、Bean实例化的两种方式
在Spring中实例化Bean有两种方式:
•通过构造方法进行实例化。默认使用无参构造。这种方式和以前new的方式是等效的。上面的第一个Spring项目其实就是这种,只需要在XML中通过<bean>的class属性指定类的全限定路径,然后就可以实例化对象。
•通过工厂进行实例化。可以通过静态工厂和实例工厂进行实例化。这种方式完全是根据设计模式中工厂模式的思想而研发出的。Spring考虑到如果需要频繁实例化某个类的对象,工厂模式无疑是一个好选择。
第一个Spring项目已经演示过第一种实例化Bean的方式,所以下面重点演示使用工厂进行实例化bean。由于工厂模式又分为静态工厂和实例工厂两种方式,所以下面分成两部分进行演示。
●使用实例工厂实例化bean
•创建工厂类
实例工厂方式需要实例化工厂类。所以工厂中创建bean的方法是一个实例方法。
在项目中创建实例工厂类,并编写方法返回创建的实例对象。
示例中创建com.bjsxt.factory.PeopleFactory
●使用静态工厂实例化bean
• 创建工厂类
静态工厂和实例工厂类最主要的区别是,创建bean的方法是static修饰的。
创建静态工厂类:com.bjsxt.factory.PeopleStaticFactory
package com.bjsxt.factory;
●属性注入的三种方式/DI注入的三种方式/给对象中属性进行赋值的操作
•有参构造
<constructor-arg</constructor-arg>
•SET方法
<property></property>
•自动注入
在Spring中,允许Bean的自动注入。有两种方式进行配置。
•在根标签<beans>中配置default-autowire属性。标签整个Spring中自动注入的策略。可取值有5个。
default:默认值。不自动注入。
no:不自动注入。
byName:通过名称自动注入。会自动寻找容器中与当前属性同名的bean进行注入。
byType:通过类型自动注入。会自动寻找容器中与当前bean类型匹配的bean进行注入。如果有多个相同类型的bean注入会出现异常。
constructor:通过构造方法进行注入。写找bean的构造方法中是否有一个包含其他bean类型的参数。如果有自动注入进去。类型先byType后byName,如果没找到不注入。
注:构造方法类型和其Bean的类型相同。
•在<beany标签中配置autowire属性。和default-autowire取值相同。唯一注意default表示全局default-autowire的值。如果autowire和default-autowire同时存在,autowire生效。
自动注入指的都是bean之间的自动注入。能够自动注入必须保证Spring容器中包含能被自动注入的bean。
六、bean标签的scope属性
Spring中<bean>的scope控制的是Bean的有效范围。
●一共6个可取值:
singleton:默认值。bean是单例的,每次获取Bean都是同一个对象。
prototype:每次获取bean都重新实例化。
request:每次请求重新实例化对象,同一个请求中多次获取时单例的。
session:每个会话内bean是单例的。
application:整个应用程序对象内bean是单例的。
websocket:同一个websocket对象内对象是单例的。
里面的singleton和prototype在Spring最基本的环境中就可以使用,不需要web环境。
但是里面的request、session、application、websocket都只有在web环境才能使用。
●Spring中Bean是否是线程安全的?
如果bean的scope是单例的,bean不是线程安全的。
如果bean的scope是prototype,bean是线程安全的。
●Spring中Bean标签的Scope作用域
•在非web环境中可以使用
singleton:默认值。bean是单例的,每次获取Bean都是同一个对象。
prototype:每次获取bean都重新实例化。
•在web环境中可以使用
request:每次请求重新实例化对象,同一个请求中多次获取时单例的。
session:每个会话内bean是单例的。
application:整个应用程序对象内bean是单例的。
websocket:同一个websocket对象内对象是单例的。
七、单例设计模式
设计模式:根据面向对象五大设计思想衍生出的23中常见代码写法,每种写法可以专门解决一类问题。
单例设计模式:保证某个类在整个应用程序中只有一个对象。
单例写法分为两种:饿汉式、懒汉式。
●饿汉式
单例:希望类只有一个
核心思想:
1. 构造方法私有
2.对外提供一个能够获取对象的方法。
饿汉式:
优点:实现简单
缺点:无论是否使用当前类对象,加载类时一定会实例化。
●懒汉式
核心思想:
1. 构造方法私有
2.对外提供一个能够获取对象的方法。
优点:
按需创建对象。不会在加载类时直接实例化对象。
缺点:
写法相对复杂
多线程环境下,第一次实例化对象效率低。
•不会立即实例化
•不是第一次访问的线程,直接通过if判断条件不成立。直接return
•防止多个线程已经执行到synchronized
八、Spring 循环注入问题
循环注入即多个类相互依赖,产生了一个闭环。
当两个类都是用构造注入时,没有等当前类实例化完成就需要注入另一个类,而另一个类没有实例化完整还需要注入当前类,所以这种情况是无法解决循环注入问题的的。会出现BeanCurrentlylnCreationException异常。
如果两个类都使用设值注入且scope为singleton的就不会出现问题,可以正常执行。因为单例默认下有三级缓存(DefaultSingletonBeanRegistry),可以暂时缓存没有被实例化完成的Bean。
但是如果两个类的scope都是prototype依然报BeanCurrentlylnCreationException。
九、BeanFactory和ApplicationContext
BeanFactory是Spring中的顶级接口,接口中定了Spring容器最基本功能。是Spring loC的最核心接口。
BeanFactory最常用实现类是XmlBeanFactory
无论是使用哪个写法,都可以发现BeanFactory是在真正getBean的时候才去实例化的。(可以通过添加输出语句,查看对象在什么时候实例化)
而ApplicationContext是BeanFactory的子接口。所以要比BeanFactory的功能更加强大,除了BeanFactory的功能,还包含了:
•AOP功能
•国际化(MessageSource)
•访问资源,如URL和文件(ResourceLoader)
•消息发送机制(ApplicationEventPublisher)
•Spring集成Web时的WebApplicationContext
在使用时ApplicationContext时多使用ClassPathXmlApplicationContext
看出ApplicationContext是在加载文件后立即创建Bean。可以通过lazy-init属性进行控制,让bean懒加载
十、Spring整合web
Spring项目不需要依赖Web环境,但是Java项目大多数是Web项目,所以Spring也支持集成到Web环境中。
Spring 集成Web环境是通过Listener实现的,在ServletContext对象创建时加载Spring容器。Spring已经在spring-web.jar包中提供了ContextLoaderListener实现加载Spring配置文件的代码。我们只需要在web.xml配置<1istener>标签让ContextLoaderListener生效,并且告诉ContextLoaderListener加载Spring配置文件的路径即可。
●创建项目,并添加依赖
创建Maven的web项目(添加上webapp目录等,并配置web模块),并在pom.xml配置依赖。
十一、Spring支持的注解(IoC/DI相关)
@Repository、@Service、@Controller、@Configuration都是@Component注解的子注解,作用相同。主要的区别是语义上的区别。当看到不同的注解放在不同层的类中。但是不按照语义去做,非把@Service用在持久层,也是有效果的。但是这样却是不规范的。
@Component 实例化Bean,默认名称为类名收字母变小写。支持自定义名称
@Repository @Component子标签。作用和@Component一样。用在持久层
@Service @Component子标签。作用和@Component一样。用在业务层
@Controller @Component子标签。作用和@Component一样。用在控制器层
@Configuration @Component子标签。作用和@Component一样。用配置类
@Autowired 自动注入。默认byType,如果多个同类型bean,使用byName(默认通过属性名查找是否有同名的bean,也可以通过@Qualifier("bean名称"),执行需要注入的Bean名称)
@Resource 非Spring注解。默认byName,如果没找到,使用byType。
●DI:依赖注入
@Autowired (是Spring提供的)先按照类型进行注入 如果类型有多个再按照名称进行注入,如果同名的没有找到,就会按照@Qualifier()指定的名称进行注入
@Resource (非Spring提供):默认按照byName进行注入,如果没有找到再按照byType进行注入
注意:如果直接写到属性上进行注入 不需要写SET方法 因为底层使用反射直接给属性进行的注入所以不需要写SET方法
IOC/DI一定使用<context:component-scan base-package="com.bjsxt.pojo"</context:component-scan>进行扫描,如果有多个包需要使用逗号分割
●需求:实现计算器功能 有4个功能 加减乘除
功能设计完成后 可能过了5年时间 现在需要对之前的每一个操作添加一个日志记录功能,
日志输出格式为:第一个数:xx 第二个数为:xxx在xxx时间 做了xxx操作
解决方案:直接修改代码即可
弊端:
•过了N年可能源代码找不到了,因为运行的时候只要字节码文件
•如果代码可以修改你修改的前提是需要先梳理之前代码结果 然后再找对应的功能再做出修改,这个操作非常的麻烦
•即使可以修改源代码可能发生修改之后代码相互调用受到了影响
目的:在不修改源代码的前提下 从而实现功能的添加扩展
解决方案:AOP AOP的整体实现思想来源于设计模式动态代理
●Aspect:切面。即join point + Advice
join point:切入点。就是我们平时说的目标方法,或说对哪个方法做扩展,做增强。
Advice:通知,增强内容。
Pointcut:切点。就是表达式,通过表达式说明哪些方法是join point
AOP Proxy:代理。Spring支持JDK动态代理和cglib动态代理两种方式,可以通过proxy-target-class=true把默认的JDK动态代理修改为Cglib动态代理。
Weaving:织入。织入就是把Advice添加到join point的过程。
在实际开发中AOP主要应用在Service层。
●AOP
AOP叫做面向切面编程,属于对OOP的扩展。其实现是基于动态代理设计模式,在loC基础上实现的。
AOP就是对某个切入点做了通知进行增强扩展,形成横切面。可以实现在不修改原有代码的情况下,做额外扩展。
十二、AspectJ实现AOP
●AspectJ方式通知类型
•前置通知before
•后置通知:after是否出现异常都执行的后置通知。after-returning切入点不出现异常时才执行的后置通知
•环绕通知around
• 异常通知after-throwing
•创建通知类
Aspectj方式实现AOP的通知类不需要实现任何的接口,直接声明一个普通java类即可,然后在类中直接定义通知方法即可,方法名随意,但是建议方法名见名知意。