主要内容
1.MyBatis整合Spring实现
2.代理设计模式
3.JDK动态代理
4.CGLIB代理
5.Spring AOP的简介
6.SpringAOP的Schema-based方式实现
一.Spring整合MyBatis
[1]如何进行整合
Spring可以将已有技术变得更好用,MyBatis是可以简化JDBC操作.
前提导包,要注意Spring默认没有提供整合MyBatis的包,由MyBatis提供,需要将整合包导进来
责任划分,MyBatis负责数据库的操作(映射文件xxxMapper.xml);
Spring负责整体的管理工作(管理数据源,管理事务,管理MyBatis,管理对象,管理AOP...)
[2]整合流程
创建爱你项目并导包:
spring相关:
spring-core,spring-beans,spring-context,spring-expression,spring-aop,commons-logging,spring-jdbc,spring-tx:管理数据源和事务
spring-web:提供web相关的资源(监听器,过滤器)
MyBatis相关:
mybatis,mysql-connector-java
log4j
整合包
mybatis-spring,注意版本信息
http://mybatis.org/spring/zh/index.html
其他包
jstl,junit,hamcrest
提供配置(重点)
db.propertie-数据库连接信息
log4j.properties-日志配置信息
spring相关配置信息(拆分)
applicationContext-service.xml-负责管理service对象
<?xml version="1.0" encoding="UTF-8">
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2002/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--此处用于管理service层对象-->
<bean id="userService" class="com.bjsxt.service.impl.UserServiceImpl">
<!--此处需要spring容器中存在userMapper对象-->
<property name="userMapper" ref="userMapper"/>
</beans>
# aplicationContext-mybatis.xml-负责管理MyBatis(整合)
<?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
http://www.springframework.org/schema/context/spring-context.xsd">
<!--spring整合MyBatis的配置信息-->
<!--加载资源文件,需要使用context命名空间-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--配置数据源:dbcp,c3p0,druid,hikariCP-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${db.driver}"/>
<property name="url" value="${db.url}">
<property name="username" value="${db.username}"/>
<property name="password" value="${db.password}"/>
</bean>
<!--mybatis-spring.jar,SqlSessionFactoryBean用于构建工厂对象-->
<bean id="factory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--数据源-->
<property name="dataSource" ref="dataSource"/>
<!--配置别名-->
<property name="typeAliasesPackage" value="com.bjsxt.pojo"/>
<!--配置映射扫描,mybatis-spring.jar,MapperScannerConfigurer-->
<bean class="org.mybatis.spring.mapper.MapperScanConfigurer">
<!--扫描位置-->
<property name="basePackage" value="com.bjsxt.mapper"/>
<!--注入工厂-->
<property name="sqlSessionFactorybeanName" value="factory"/>
</bean>
</beans>
applicationContext-tx.xml-负责事物管理(见第四节)
MyBatis配置信息
映射文件-定义SQL语句
web.xml-配置监听器,过滤器
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp/xml/ns/javaee/web-app_4_0.xsd"
version="4.0"
<!--全局参数,配置spring配置文件位置-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!--监听器-->
</listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
[3]代码编写
a)pojo(略)
b)jsp
<table>
<tr>
<td>编号</td>
<td>用户名</td>
<td>姓名</td>
<td>年龄</td>
<td>生日</td>
<td>注册时间</td>
<td>操作</td>
</tr>
<c:forEach items="${list}" var="u">
<tr>
<td>${u.id}</td>
<td>${u.username}</td>
<td>${u.realname}</td>
<td>${u.age}</td>
<td>${u.birthday}</td>
<td>${u.regTime}</td>
<td>
<a href="delUser?id=${u.id}" onclick="return confirm('确定要删除吗?');">删除</a>
</td>
</tr>
</forEach>
</table>
c)servlet
@WebServlet("/userList")
public class UserListServlet extends HttpServlet{
private UserService userService;
@Override
public void init()throws ServletException{
//从aplication作用域中拿到spring容器
WebApplicationContext context=
WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
//为userService赋值
this.userService=context.getBean("userService",UserService.class);
}
@Override
protected void service(HttpServletRequest req,HttpServletResponse resp)throws ServletException,IOException{
//调用服务层方法获取用户列表集合
List<User>list = this.userService.userList();
//保存到作用域
req.setAttribute("list",list);
//页面跳转
req.getRequestDispatcher("/index.jsp").forward(req,resp);
}
}
@WebServlet("/delUser")
public class UserDelServlet extends HttpServlet{
private UserServcie userService;
@Override
public void init() throws ServletException{
WebApplicationContext context = WebApplicationContextUtils.getRequiresWebApplicationContext(getServletContext());
this.userService = context.getBean("userService",UserService.class);
}
@Override
protected void service(HttpServletRequest req,HttpServletResponse resp)throws ServletException,IOException{
//接受参数
int id = Integer.parseInt(req.getParameter("id"));
//调动服务方法进行删除操作
userService.delUser(id);
//重新查询用户列表
resp.sendRedirect(req.getContextPath()+"/userList");
}
}
d)service
public class UserServiceImpl implements UserService{
//需要在spring创建userService对象时将userMapper进行注入
private UserMapper userMapper;
public UserMapper getUserMapper(){
return userMapper;
}
@Override
public void delUser(int id){
userMapper.delUser(id);
}
public void setUserMapper(UserMapper userMapper){
this.userMapper = userMapper;
}
@Override
public List<User>userList(){
return userMapper.selAll();
}
}
e)mapper
public interface UserMapper{
List<User>selAll();
void delUser(int id);
}
<?xml version="1.0" encoding="UTF-8">
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="con.bjsxt.mapper.UserMapper">
<select id="selAll" resultType="user">
select id,username,password,realname,age,birthday,reg_time regTime from tb_user
</select>
<delete id="delUser">
delete from tb_user where id=#{id}
</delete>
</mapper>
二.代理模式
[1]设计模式
解决某一类问题的产生
静态代理
代理模式{
动态代理[JDK动态代理,CGLIB动态代理]
}
[2]代理模式的角色
A.抽象的类或者接口--定义完成一件怎样的事情
B.代理对象--完成这件事情的对象
C.被代理对象--完成事件背后的隐藏的内容
[3]代理模式案例
我们找中介租房子
抽象的类或者接口--租房子
被代理对象--房东
代理对象--中介
[4]代理模式的好处
A.房东安心的做自己的事情即可.不用锅里其他的事情
B.房东对象比较的安全
C.增强了代码的扩展性
[5]静态代理
优点:上述内容
缺点:在中介里面随着房东对象的增多,中介的压力就会越来越大,体现到代码上就是代码越来越臃肿
特点是dialing对象是针对指定的目标做的,所有代码都固定的,由程序员提供.代码实现非常简单,不能复用
三.JDK动态代理
[1]代码实现
public class MyInvoction implements InvocationHandler{
private RentRoom rm;
public void setRm(RentRoom rm){
this.rm = rm;
}
//动态获取代理类对象--中介
/**
参数一:ClassLoader类加载器
参数二:new Class[]{}
参数三:InvocationHandler
*/
public Object getproxy(){
return Proxy.newProxyInstance(MyInvocation.class.getClassLoader(),new Class[]{RentRoom.class},this);
}
/**
租房的方法
*/
@Override
public Object invoke(Object proxy,Method method,Object[] args)throws Throwable{
System.out.println("收取介绍费500元");
Object invoke = method.invoke(rm,args);
System.out.println("收取卫生费400元");
return invoke;
}
}
[2]理解示意图
四.CGLIB动态代理
[1]JDK动态代理存在的问题
JDK代理的产生必须要实现对应的接口的,如果没有对应的接口,这个时候dialing对象就没有办法产生
[2]解决的方案
CGLIB
public class MyMethodIn implements methodInterceptor{
//动态产生代理对象
public Object getProxy(){
Enhancer en = new Enhancer();
//设置父类
en.setSuperclass(FD1.class);
//设置回滚函数
en.setCallback(this);
//使整个设置生效
Object o = en.create();
return o;
}
@Override
public Object intercept(Object o,Method method,Object[] objects,MethodProxy methodProxy)throws Throwable{
System.out.println("收取管理费500元");
//调用房东的租房方法
Object o1 = methodProxy.invokeSuper(o,objects);
System.out.println("收取卫生费400");
return o1;
}
}
poublic class TestA{
public static void main(String[] args){
MyMethodIn my = new MyMethodIn();
FD1 proxy = (FD1)my.getProxy();
proxy.zf();
}
}
五.AOP的简介
[1]为什么使用AOP
IOC:控制反转--帮我们创建对象--实现解耦
AOP:面向切面编程--提升代码的扩展性
[2]AOP的简介
AOP的概念:Aspect Oriented Programming
Aop的中文:面向切面编程
通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术
利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合性降低,提高程序的可重用性.同时提高了开发效率
[3]AOP中的几个要素
A.切点:在执行的过程中的每一个方法都可以看做是一个切点
B.通知:
前置通知:在切点之前执行的通知称为前置通知
后置通知:在切点之后执行的通知称之为后置通知
环绕通知:在切点前和后都会执行的通知称之为环绕通知
异常通知:当切点方法报错时候执行的通知称之为异常通知
C.切面:横切面
[4]AOP实现的两种方式
A.schema base
B.AspectJ
[5]理解示意图
六.SpringAOP的Schema-based方式实现
[1]Scheam-based方式实现的基本流程
SpringAOP的本质总结:
我们将要进行功能扩展相关的材料以及对应的组织规则告诉Spring容器,Spring容器帮我们动态创建一个代理对象.我们直接从Spring容器中获取代理对象完成功能开发.
1)导入SpringAOP的jar包
2)在src下创建包advice,并创建前置通知类和后置通知类
前置通知类
创建一个普通的java类,实现MethodBeforeAdvice接口,重写before方法,在before方法中声明扩展前的逻辑代码.
后置通知类:
创建一个普通的Java类,实现AfterReturningAdvide接口,重写after方法,并在after方法中声明扩展后的逻辑代码
3)在applicationcontext.xml文件中配置资源的bean对象以及声明组装规则.
资源对象:
要进行功能扩展的bean对象
前置通知的bean对象
后置通知的bean对象
声明组装规则:(使用AOP标签完成)
声明切点:
声明组装
4)从Spring容器中直接获取代理对象完成功能开发
注意:如果让Spring容器对象某个bean对象按照AOP进行功能扩展,则从Spring容器中使用该对象的ID获取的对象已经不是其本身了.而是他的代理对象(夺舍)
[2]SpringAOP的专业概念:
真实对象:要进行工鞥呢扩展的对象,相当于A对象
代理对象:完成功能扩展的对象,相当于B对象
切点:要进行功能扩展的方法,相当于testA()方法
前置通知方法:在切点之前执行的扩展方法
后置通知方法:在切点之后执行的扩展方法
切面:由前置通知+切点+后置通知形成的横向执行的面
织入:由前置通知+切点+后置通知形成切面的过程
AOP的概念:面向切面的编程
[3]Schema-based方式环绕通知方式实现AOP
解释:
前面我们已经使用前置通知方式和后置通知方式完成了AOP的扩展代码的编写.而我们之前学习过过滤器的概念.在过滤器中会先执行一部分代码,执行后如果放行了则继续执行Servlet,Servlet执行后再次会到过滤器中执行.那么,从AOP的角度过滤器就相当于Servlet的扩展对象了.过滤器中的拦截方法,就相当于扩展方法,而我们将扩展代码和调用原有切点方法的代码全部直接声明在一个方法中了,那么能不能采用此种方案来完成我们会自己的AOP扩展呢?
实现:
环绕通知
特点:
将扩展代码和调用原有切点方法的代码声明在一起,简化扩展流程.也就说环绕通知中包含了前置通知和后置通知
使用:
1)创建一个普通的Java类,实现环绕通知的接口
2)在applicationcontext.xml文件中配置环绕通知的bean
3)在组装规则中使用配置环绕通知的组装
注意:前置通知和后置通知和环绕通知可以同时使用,执行顺序和配置顺序相关.
[4]Schema-based方式的异常通知
问题:
在我们封装了一个功能方法时,一般方法处理数据所造成的异常信息需要抛出,或者代码编译没有问题,运行期间出现问题,带异常也应该有调用者来处理.那么在SpringAOP中,代理对象是动态生成的,在代理对象中会调用前置通知,后置通知,环绕通知,切点方法,那么如果这些方法出现异常信息,理论对象是动态生成的,不是由我们创建类然后根据类文件创建出来的,那么我们就无法直接的声明异常处理代码了,怎么办呢?
解决:
在外部声明异常处理的功能方法,让SpringAOP动态生成的代理对象,在生成的catch中调用我们声明的异常处理方法即可
使用:
1)创建一个普通Java类,实现异常接口
2)在applicationcontext.xml文件中配置异常通知bean对象
3)在applicationcontext.xml文件中配置异常通知bean的组装
[5]SpringAOP的切点的声明格式
1)切点是某包某类的无参数的方法
示例:
execution(*com.bjsxt.service.impl.Student.test())
2)切点是某包某类带有参数的方法
示例:
execution(*com.bjsxt.service.impl.Student.test(String,int))
3)切点是某包某类的某个同名的所有方法
示例:..表示任意个数任意类型的参数
execution(*com.bjsxt.service.impl.Student.test(..))
4)切点是某包下的某类的所有方法
示例:*表示任意的类名,方法名,包名
execution(*com.bjsxt.service.impl.Student.*(..))
5)切点是某包下的所有类的所有方法
示例:*表示任意的类名,方法名,包名
execution(*com.bjsxt.service.impl.*.*(..))
七.SpringAOP的Schema-based方法的参数
[1]前置通知
使用:
1)声明一个普通JAVA类,实现BeforeAdvice接口
2)在Spring配置文件中配置前置通知的bean对象
3)配置组装
方法:
方法名:before
调用者:代理对象中的扩展方法调用
方法体:声明切点之前执行的扩展代码
参数:
Method method,
Object[] object,
Object o
参数的作用:
[2]后置通知
使用:
1)声明一个普通Java类,实现AfterReturningAdvice接口
2)在Spring配置文件中配置后置通知的bean对象
3)配置组装
方法:
方法名:after
调用者:代理对象中的扩展方法调用
方法体:声明切点之后执行的扩展代码
参数:
Object o,
Method method,
Object[] objects,
Object o1
参数的作用:
[3]环绕通知
使用:
1)声明一个普通JAVA类,实现MethodInterceptor接口
2)在Spring配置文件中排至环绕通知的bean对象
3)配置组装
方法:
方法名:invoke
调用者:代理对象中的扩展方法调用
方法体:声明扩展代码同时根据需求是否放行
参数:
MethodInvocation methodInvocation
参数的作用:
[4]异常通知:
使用:
1)声明一个普通Java类,实现ThrowAdvice接口
2)在Spring配置文件中配置异常通知的bean对象
3)配置组装
方法:
方法名:afterThrowing
调用者:代理对象中的扩展方法的catch中调用
方法体:根据异常信息处理异常
参数:
Exception ex
参数的作用:
获取异常信息