四、spring之AOP
1.AOP基本概念
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术
面向切面编程(也叫面向方面编程):Aspect Oriented Programming(AOP),是软件开发中的一个热点,也是 Spring框架中的一个重要内容。利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
知识点(核心基础概念):切面、横切关注点,连接点,通知、切入点
- (1)通知(Advice)
就是你想要的功能,比如 安全,事务,日志,性能测试,缓存机制等。需要先定义好,然后在想用的地方用一下。 - (2)连接点(JoinPoint)
是spring允许你使用通知的地方,基本每个方法的前,后(两者都有也行),或抛出异常时都可以是连接点,spring只支持方法连接点.和方法有关的前前后后(抛出异常),都是连接点。 - (3)切入点(Pointcut)
上面说的连接点的基础上,来定义切入点,你的一个类里,有15个方法,那就有几十个连接点,但是你并不想在所有方法附近都使用通知(使用叫织入),你只想让其中的几个,在调用这几个方法之前,之后或者抛出异常时干点什么,那么就用切点来定义这几个方法,让切点来筛选连接点,选中那几个你想要的方法。 - (4)切面(Aspect)
切面是通知和切入点的结合。通知说明了干什么和什么时候干(什么时候通过方法名中的before,after,around等就能知道),而切入点说明了在哪干(指定到底是哪个方法),这就是一个完整的切面定义。 - (5)引入(introduction)
允许向现有的类添加新方法属性。就是把切面(也就是新方法属性:通知定义的)用到目标类中 - (6)目标(target)
引入中所提到的目标类,也就是要被通知的对象,也就是真正的业务逻辑,可以被织入切面。而自己专注于业务本身的逻辑。 - (7)代理(proxy)
怎么实现整套aop机制的,都是通过代理 - (8)织入(weaving)
把切面应用到的目标对象来创建新的代理对象的过程。spring采用的是运行时
关键就是:切点定义了哪些连接点会得到通知
2.AOP主要的应用
日志记录,性能统计,安全控制(权限管理),事务处理,异常处理等等
3.AOP代理模式概念
(1)静态代理
class A{
a(){
业务逻辑代码;
}
}
class Aproxy{
A a;//把要被代理的类引入进来
setA(A a){
this.a = a;
}
a(){
aspect();//日志处理的切面方法
a.a();
}
aspect(){
日志管理;
}
}
静态代理: 能完成增强功能的作用
缺点:每一个类都需要定义对应代理类,工作量比较大
(2)动态代理,运行时动态生成一个类(利用反射)
- JDK动态代理
要求:目标类必须实现接口,使用接口创建一个代理类, 目标类和代理类实现同一个接口
特点:使用jdk代理类,使用jdk自带类,不需要导入额外的包
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Date;
public class LogHandler implements InvocationHandler {
Object target; // 被代理的对象,实际的方法执行者
public LogHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object result = method.invoke(target, args);// 调用 target 的 method 方法
after();
return result; // 返回方法的执行结果
}
// 调用invoke方法之前执行
private void before() {
System.out.println(String.format("log start time [%s] ", new Date()));
}
// 调用invoke方法之后执行
private void after() {
System.out.println(String.format("log end time [%s] ", new Date()));
}
}
import proxy.UserService;
import proxy.UserServiceImpl;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class Client2 {
public static void main(String[] args) throws IllegalAccessException, InstantiationException {
// 设置变量可以保存动态代理类,默认名称以 $Proxy0 格式命名
// System.getProperties().setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
// 1. 创建被代理的对象,UserService接口的实现类
UserServiceImpl userServiceImpl = new UserServiceImpl();
// 2. 获取对应的 ClassLoader
ClassLoader classLoader = userServiceImpl.getClass().getClassLoader();
// 3. 获取所有接口的Class,这里的UserServiceImpl只实现了一个接口UserService,
Class[] interfaces = userServiceImpl.getClass().getInterfaces();
// 4. 创建一个将传给代理类的调用请求处理器,处理所有的代理对象上的方法调用
// 这里创建的是一个自定义的日志处理器,须传入实际的执行对象 userServiceImpl
InvocationHandler logHandler = new LogHandler(userServiceImpl);
/* 5.根据上面提供的信息,创建代理对象 在这个过程中,
a.JDK会通过根据传入的参数信息动态地在内存中创建和.class 文件等同的字节码
b.然后根据相应的字节码转换成对应的class,
c.然后调用newInstance()创建代理实例 */
UserService proxy = (UserService) Proxy.newProxyInstance(classLoader, interfaces, logHandler);
// 调用代理的方法
proxy.select();
proxy.update();
// 保存JDK动态代理生成的代理类,类名保存为 UserServiceProxy
// ProxyUtils.generateClassFile(userServiceImpl.getClass(), "UserServiceProxy");
}
}
CGLIB动态代理
特点:代理类继承了目标类,不需要目标类实现接口
导包
注意:目标类和方法不能使用final修饰
4.AOP的应用实例:
应用要求
(1)前置通知;
(2)后置通知;
(3)环绕通知;
(4)返回通知;
(5)异常通知;
使用aop的步骤
(一)使用XML配置文件定义AOP
(1)导入jar包
Aop需要最基础的包
spring-aop.jar
aspectjweaver.jar
注:maven导入aspectjweaver时把runtime去掉,不然找不到JoinPoint
-
(2)构建通知类
public void doReturn(JoinPoint jp){ } public void doException(JoinPoint jp,Throwable ta){
-
(3)spring配置(通知、切面、切入点等)
xml添加aop头部信息
配置aop设置
注意:xml配置通知顺序有影响
doAfter一般在doAround之后配置
5.切点表达式
<aop:pointcut expression=“execution(* org.lanqiao.service.*
.*
(…))” id=“studentPointCut”/>
切点表达式:1.第一个*
表示返回值类型任意
2.第二个*
表示service包下的所有类包括子包的类
3.第三个*
表示类中任意的方法
4. ..
表示任意参数类型和个数包括0个
5.此切点表达式表示service包下所有类的所有方法都作为切入点,前置通知等都会切入
(二)使用注解的方式定义AOP
beans.xml
<!--设置注解的方式来使用AOP-->
<aop:aspectj-autoproxy/>
或者使用配置类的时候,在配置类上可以加上@EnableAspectJAutoProxy
在通知类上使用注解
package org.lanqiao.advisor;
/**
* 通知类
*/
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Component
@Aspect //定义当前类作为切面类,作为切面一个部分
public class StudentLogAdvisor {
Logger logger = Logger.getLogger(StudentLogAdvisor.class);
@Pointcut("execution(* org.lanqiao.service.*.*(..))")
public void abc(){ }
@Before("abc()")
public void doBefore(JoinPoint jp){
logger.info("before 在业务之前执行.......................");
}
@After("abc()")
public void doAfter(){
logger.info("after 在业务之后执行.......................");
}
@AfterReturning("abc()")
public void doReturn(){
logger.info("return 在业务方法返回之前执行。。。。。。");
}
@Around("abc()")
public void doAround(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("around before.............");
pjp.proceed();
System.out.println("around after...........");
}
}
四、spring对jdbc支持(IOC) 了解
Spring 对jdbc 使用 JdbcTemplate
(1)导入jdbc与tx(事务)包
(2)使用dbcp数据源,导入jar包
常用的数据源:C3P0,DBCP,DRUID,HikariCP
spring data jpa—》hibernate
(3)按以下步骤设置
添加头部,加载属性文件,设置数据源,使用JdbcTemplate,设置dao注入及service注入
(4)dao层使用JdbcTemplate进行增删改查操作(只是spring提供简化了jdbc操作的一种方式)