05-Spring02-AOP
今日知识
1. AOP
2. AspectJ
3. JdbcTemplate
AOP
1. AOP :Aspect Oriented Programming,意为面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
1. 好处
* 利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
* AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码
* 经典应用:事务管理,性能监视,安全检查,缓存,日志。
* SpringAOP使用纯的java实现,不需要专门的编译过程和类加载器,在运行期通过代理方式向目标类织入增强代码
* AspectJ是一个基于Java语言的AOP框架,Spring2.0开始,Spring AOP引入对Aspect的支持,AspectJ扩展了Java语言,提供了一个专门的编译器,在编译时提供横向代码的织入
2. AOP实现原理
1. AOP底层将采用代理机制进行实现
2. 接口+实现类:Spring采用jdk的动态代理Proxy
3. 实现类:Spring采用cglib字节码增强
3. AOP术语
1. target:目标类,需要被代理的类。例如:UserService
2. Joinpoint(连接点):所谓连接点是指那些可能被拦截到的方法。例如:所有的方法
3. PointCut 切入点:已经被增强的连接点。例如:addUser()
4. advice 通知/增强,增强代码。例如:after、before
5. Weaving(织入):是指把增强advice应用到目标对象target来创建新的代理对象proxy的过程.
6. proxy 代理类
7. Aspect(切面): 是切入点pointcut和通知advice的结合
一个线是一个特殊的面。
一个切入点和一个通知,组成成一个特殊的面。
4. 手动代理
1. JDK动态代理
* 和原来的方法一样
2. cglib增强字节码
1. 导入jar包:
2. 没有接口,只有实现类。
//cglib代理
@Test
public void test2(){
final UserService1 userService=new UserService1();
UserService1 proxy = (UserService1) Enhancer.create(UserService1.class, new InvocationHandler() {
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
System.out.println("开启事务");
Object invoke = method.invoke(userService, objects);
System.out.println("提交事务");
return invoke;
}
});
proxy.addUser();
}
5. Spring编写代理半自动
1. jar
2. 目标类
* public class UserService1 {
public void addUser() {
System.out.println("添加用户");
}
}
3. 切面类
* public class MyAspect2 implements MethodInterceptor{
public Object invoke(MethodInvocation mi) throws Throwable {
System.out.println("开启事务");
Object invoke = mi.proceed();
System.out.println("提交事务");
return invoke;
}
}
4. spring配置
* <!--业务类-->
<bean id="userService" class="com.rqy.service.UserService1"/>
<!--切面类-->
<bean id="myAspect" class="com.rqy.aspect.MyAspect2"/>
<!--使用工厂bean创建代理-->
<bean id="proxyService" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="userService"/>
<property name="interceptorNames" value="myAspect"/>
</bean>
5. test
* @Autowired
@Qualifier("proxyService")
UserService1 userService;
@Test
public void test3(){
userService.addUser();
}
6. Spring编写代理半自动升级版(通过配置类方式,同时注解注入)
1. jar
2. 目标类
@Component("userService")
* public class UserService1 {
public void addUser() {
System.out.println("添加用户");
}
}
3. 切面类
* //注解注入
* @Component("mymethod")
* public class MyAspect2 implements MethodInterceptor{
public Object invoke(MethodInvocation mi) throws Throwable {
System.out.println("开启事务");
Object invoke = mi.proceed();
System.out.println("提交事务");
return invoke;
}
}
4. 配置类
* //告诉spring这是一个配置类
@Configuration
public class SpringConfig {
//在配置中注册组件
//注册第三方或者已经编译过得类
//如果bean里面不写,默认方法名当做bean的id
@Bean("proxyFactoryBean")
public ProxyFactoryBean proxyFactoryBean(@Qualifier("userService") UserService userService){
ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
proxyFactoryBean.setTarget(userService);
proxyFactoryBean.setInterceptorNames("mymethod");
return proxyFactoryBean;
}
}
5. spring配置
*<!--注解开关-->
<context:component-scan base-package="com.rqy"/>
5. test
* @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:application.xml")
public class MyTest {
@Autowired
@Qualifier("proxyFactoryBean")
UserService userService;
@Test
public void test(){
userService.addUser();
}
}
AspectJ全自动编程
1. 导包
* dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>
2. 切面类
public class MyAspect implements MethodInterceptor{
public Object invoke(MethodInvocation mi) throws Throwable {
System.out.println("开启事务");
Object invoke = mi.proceed();
System.out.println("提交事务");
return invoke;
}
}
Spring的AOP配置
* <!--切面类-->
<bean id="myAspect" class="com.rqy.aspect.MyAspect"/>
<!--
AOp编程步骤
1. 导入命名空间
2. proxy-target-class="true" 默认使用cglib代理
3. aop:pointcut
切入点表达式:execution(* com.rqy.*.*(..))
选择方法 包 类名任意 方法名任意 参数任意
切入面:advice-ref:通知
pointcut-ref:切入点的引入
-->
<aop:config proxy-target-class="true">
<aop:pointcut id="myPointCut" expression="execution(* com.rqy.service.*.*(..))"/>
<aop:advisor advice-ref="myAspect" pointcut-ref="myPointCut"/>
</aop:config>
3. 测试
* @Autowired
@Qualifier("userService")
UserService userService;
@Test
public void test(){
userService.addUser();
}
AspectJ
1. AspectJ简介
* AspectJ是一个基于Java语言的AOP框架
* Spring2.0以后新增了AspectJ切点表达式的支持
* @AspectJ 是AspectJ1.5新增功能,通过JDK5注解技术,允许直接在Bean类中定义切面
* 新版本Spring框架,建议使用AspectJ方式来开发AOP
* 主要用途:自定义开发
2. Aspect案例讲解
1. 导包
* AOP联盟规范:aopalliance
* AOP实现:spring-aop
* 规范:aspectjweaver
* aspectj实现:spring-aspects
2. 实现类:和上面一样
3. 切面类:
* public class MyAspect2 {
public void myBefore(JoinPoint jp){
System.out.println("前置通知"+jp.getSignature().getName());//连接点的方法名
}
public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕通知 前");
//获取切入点方法名
String name = joinPoint.getSignature().getName();
System.out.println(name);
Object proceed = joinPoint.proceed();
System.out.println("环绕通知 后");
return proceed;
}
public void myAfterReturnning(JoinPoint jp,Object e){
System.out.println("后置通知:"+e);
}
public void myAfterThrowing(JoinPoint jp,Throwable e){
System.out.println("异常通知:"+e.getMessage());
}
public void myAfter(){
System.out.println("最终通知");
}
}
4. spring配置
* <!--业务类-->
<bean id="userService" class="com.rqy.service.UserService"/>
<!--切面类-->
<bean id="myAspect" class="com.rqy.aspect.MyAspect2"/>
<!--
AOp编程步骤
1. 导入命名空间
2. proxy-target-class="true" 默认使用cglib代理
3. aop:pointcut
切入点表达式:execution(* com.rqy.*.*(..))
选择方法 包 类名任意 方法名任意 参数任意
切入面:advice-ref:通知
pointcut-ref:切入点的引入
-->
<!-- <aop:config proxy-target-class="true">
<aop:pointcut id="myPointCut" expression="execution(* com.rqy.service.*.*(..))"/>
<aop:advisor advice-ref="myAspect" pointcut-ref="myPointCut"/>
</aop:config>-->
<aop:config>
<aop:aspect ref="myAspect">
<aop:pointcut id="myPoinrCut" expression="execution(* com.rqy.service.*.*(..))"/>
<!--前置通知-->
<aop:before method="myBefore" pointcut-ref="myPoinrCut"></aop:before>
<!--环绕通知-->
<aop:around method="myAround" pointcut-ref="myPoinrCut"></aop:around>
<!--异常通知-->
<aop:after-throwing method="myAfterThrowing" pointcut-ref="myPoinrCut" throwing="e"></aop:after-throwing>
<!--后置通知,用于获取返回值-->
<aop:after-returning method="myAfterReturnning" pointcut-ref="myPoinrCut" returning="e"></aop:after-returning>
<!--最终通知 有没有异常都会走最终通知-->
<aop:after method="myAfter" pointcut-ref="myPoinrCut"></aop:after>
</aop:aspect>
</aop:config>
3. AspectJ基于xml的讲解
1. 上面的案例
4. AspectJ注解的讲解
1. @Aspect 声明切面,修饰切面类,从而获得 通知。
2. @Before 前置
3. @AfterReturning 后置
4. @Around 环绕
5. @AfterThrowing 抛出异常
6. @After 最终
7. 切入点 ,@PointCut ,修饰方法 private void xxx(){} 之后通过“方法名”获得切入点引用
8. xml需要开启 <!--aop注解生效-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
9. 案例
@Component
@Aspect
public class MyAspect3 {
//声明共用切入点
@Pointcut("execution(* com.rqy.service.*.*(..))")
public void myPointCut(){
}
@Before(value = "myPointCut()")
public void myBefore(JoinPoint jp){
System.out.println("前置通知"+jp.getSignature().getName());//连接点的方法名
}
@Around(value = "myPointCut()")
public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕通知 前");
//获取切入点方法名
String name = joinPoint.getSignature().getName();
System.out.println(name);
Object proceed = joinPoint.proceed();
System.out.println("环绕通知 后");
return proceed;
}
@AfterReturning(value = "myPointCut()",returning = "e")
public void myAfterReturnning(JoinPoint jp,Object e){
System.out.println("后置通知:"+e);
}
@AfterThrowing(value = "myPointCut()",throwing = "e")
public void myAfterThrowing(JoinPoint jp,Throwable e){
System.out.println("异常通知:"+e.getMessage());
}
@After(value = "myPointCut()")
public void myAfter(){
System.out.println("最终通知");
}
}
切入点表达式
1. 语法:execution(修饰符 返回值 包.类.方法名(参数) throws异常)
2. 修饰符,一般省略
public 公共方法
* 任意
返回值,不能省略
void 返回没有值
String 返回值字符串
* 任意
包,[省略]
com.gyf.crm 固定包
com.gyf.crm.*.service crm包下面子包任意 (例如:com.gyf.crm.staff.service)
com.gyf.crm.. crm包下面的所有子包(含自己)
com.gyf.crm.*.service.. crm包下面任意子包,固定目录service,service目录任意包
类,[省略]
UserServiceImpl 指定类
*Impl 以Impl结尾
User* 以User开头
* 任意
方法名,不能省略
addUser 固定方法
add* 以add开头
*Do 以Do结尾
* 任意
(参数)
() 无参
(int) 一个整型
(int ,int) 两个
(..) 参数任意
throws ,可省略,一般不写。
3. 案例1:
execution(* com.gyf.crm.*.service..*.*(..))
案例2:或
<aop:pointcut expression="execution(* com.gyf.crm.service.*.*(..)) ||
execution(* com.gyf.*Do.*(..))" id="myPointCut"/>
JdbcTemplate
1. 导包
1. 数据库驱动包
2. Spring对数据库支持的两个包
* spring-jdbc-4.2.4.RELEASE
* spring-tx-4.2.4.RELEASE
3. +1连接池 c3p0 一个 (或者JDBC 两个)
* c3p0一个包
* 或者 dbcp包+pool包
2. @Test
public void test(){
//1.创建数据源
BasicDataSource dataSource=new BasicDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/spring_day04?serverTimezone=UTC");
dataSource.setUsername("root");
dataSource.setPassword("123456");
//创建模板
JdbcTemplate jdbcTemplate=new JdbcTemplate(dataSource);
String sql="insert into t_user values (null,?,?)";
jdbcTemplate.update(sql,"tom","123");
}
3. xml配置的方式(DBCP)
* <!--dbcp数据源-->
<bean id="dataSource" class="org.apache.tomcat.dbcp.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/spring_day04?serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="userDao" class="com.rqy.dao.impl.UserDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
4. xml配置的方式(C3P0)
* <!--c3p0数据源
参数不太一样
-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring_day04?serverTimezone=UTC"/>
<property name="user" value="root"/>
<property name="password" value="123456"/>
</bean>
5. UserDaoImpl类
* public class UserDaoImpl implements UserDao {
JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public void addUser(User user) {
String sql="insert into t_user values (null,?,?)";
jdbcTemplate.update(sql,user.getUsername(),user.getPassword());
}
}
6. 使用JdbcDaoSupport(优化Bean配置)
1. 每个DAO都需要声明template 而且要写set方法。所以让DAO继承与该类,不用写这部分代码了
2. dao层变化
* public class UserDaoImpl extends JdbcDaoSupport implements UserDao {
public void addUser(User user) {
String sql="insert into t_user values (null,?,?)";
this.getJdbcTemplate().update(sql,user.getUsername(),user.getPassword());
}
}
3. xml配置的方式
* <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring_day04?serverTimezone=UTC"/>
<property name="user" value="root"/>
<property name="password" value="123456"/>
</bean>
<bean id="userDao" class="com.rqy.dao.impl.UserDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
05-Spring02-AOP的更多相关文章
- 第05章 AOP细节
第05章 AOP细节 1.切入点表达式 1.1 作用 通过表达式的方式定位一个或多个具体的连接点. 1.2 语法细节 ①切入点表达式的语法格式 execution([权限修饰符] [返回值类型] [简 ...
- Spring AOP学习笔记05:AOP失效的罪因
前面的文章中我们介绍了Spring AOP的简单使用,并从源码的角度学习了其底层的实现原理,有了这些基础之后,本文来讨论一下Spring AOP失效的问题,这个问题可能我们在平时工作中或多或少也会碰到 ...
- Spring事务Transaction配置的五种注入方式详解
Spring事务Transaction配置的五种注入方式详解 前段时间对Spring的事务配置做了比较深入的研究,在此之间对Spring的事务配置虽说也配置过,但是一直没有一个清楚的认识.通过这次的学 ...
- Spring框架简单介绍
原文地址: http://my.oschina.net/myriads/blog/37922 1.使用框架的意义与Spring的主要内容 随着软件结构的日益庞大,软件模块化趋势出现,软件开发也须要多 ...
- JAVAEE——spring02:使用注解配置spring、sts插件、junit整合测试和aop演示
一.使用注解配置spring 1.步骤 1.1 导包4+2+spring-aop 1.2 为主配置文件引入新的命名空间(约束) 1.3 开启使用注解代替配置文件 1.4 在类中使用注解完成配置 2.将 ...
- Spring框架学习05——AOP相关术语详解
1.Spring AOP 的基本概述 AOP(Aspect Oriented Programing)面向切面编程,AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码(性能监视.事务管理.安全检查 ...
- spring-02
spring-02 1.谈谈你对 Spring 的理解 Spring 是一个开源框架,为简化企业级应用开发而生.Spring 可以是使简单的 JavaBean 实现以前只有 EJB 才能实现的功能.S ...
- 面向切面编程AOP
本文的主要内容(AOP): 1.AOP面向切面编程的相关概念(思想.原理.相关术语) 2.AOP编程底层实现机制(动态代理机制:JDK代理.Cglib代理) 3.Spring的传统AOP编程的案例(计 ...
- PostSharp AOP
使用PostSharp 在.NET 平台上实现 AOP 摘要 本文首先介绍AOP(面向方面编程)的相关概念及理论,然后介绍如何使用PostSharp框架在.NET平台上实现AOP,最后对PostS ...
- Spring aop——前置增强和后置增强 使用注解Aspect和非侵入式配置
AspectJ是一个面向切面的框架,它扩展了java语言,定义了AOP语法,能够在编译期提供代码的织入,所以它有一个专门的编译器用来生成遵守字节码字节编码规范的Class文件 确保使用jdk为5.0以 ...
随机推荐
- docker学习1--dockerfile
记录docker学习过程 实践启动一个redis server 命令之前 要弄懂 dockfile 镜像 容器 三者概念以及三者之间的关系 dockerfile格式 # Comment 注释 INST ...
- 基于Java+HttpClient+TestNG的接口自动化测试框架(四)-------参数存取处理
在真正开始接口测试之前,我们需要对参数的处理进行梳理.这里所说的“参数”,既包含之前在xml中的配置(我们称之为全局参数),也包含在每一条用例中书写的param.全局参数为固定不变的,而根据接口相应获 ...
- Java架构师线上问题排查,这些命令程序员一定用得到!
Java架构师线上问题排查,这些命令程序员一定用得到! 线上问题排查,以下场景,你遇到过吗? 一.了解机器连接数情况 问题:1.2.3.4的sshd的监听端口是22,如何统计1.2.3.4的sshd服 ...
- 三分钟网络基础-IP地址分类
IP 地址的编址方法共经过了三个历史阶段: 分类的 IP 地址 子网的划分 超网 这篇文章首先介绍,最初始的 IP 地址分类方法. 分类的 IP 将 IP 地址划分为若干个固定类,每一类地址都由两个固 ...
- Java入门 - 语言基础 - 04.对象和类
原文地址:http://www.work100.net/training/java-object-class.html 更多教程:光束云 - 免费课程 对象和类 序号 文内章节 视频 1 概述 2 J ...
- 造轮子-toast组件的实现(下)
1.解决 toast 中传入 html 的问题,通过假的 slot 来实现 // plugins.js toast.$slots.default = [message] // toast.vue &l ...
- PHP——数组
数组的定义 数组能够在单个变量中存储多个值. 创建空数组: $arr = array();//表示创建一个空数组,并把创建的空数组赋值给变量$arr 数值数组 自动分配 ID 键(ID 键总是从 0 ...
- (转自360安全客)深入理解浏览器解析机制和XSS向量编码
(译者注:由于某些词汇翻译成中文后很生硬,因此把相应的英文标注在其后以便理解.这篇文章讲的内容很基础,同时也很重要,希望对大家有所帮助.) 这篇文章将要深入理解HTML.URL和JavaScript的 ...
- 51Nod 2026 Gcd and Lcm
题目传送门 分析: 开始玩一个小小的trick 我们发现\(f(n)=\sum_{d|n}\mu(d)\cdot d\)是一个积性函数 所以: \(~~~~f(n)=\prod f(p_i^{a_i} ...
- 史上最详细的二叉树、B树,看不懂怨我
今天我们要说的红黑树就是就是一棵非严格均衡的二叉树,均衡二叉树又是在二叉搜索树的基础上增加了自动维持平衡的性质,插入.搜索.删除的效率都比较高.红黑树也是实现 TreeMap 存储结构的基石. 1.二 ...