Spring之AOP面向切面编程和JDBC
文章目录
- 一、动态代理Proxy:
- spring aop
- 通过注解方式
- 表达式标签
- 注解方式类型的顺序:
- Spring-JDBC
一、动态代理Proxy:
利用Java的反射技术(Java Reflection),在运行时创建一个实现某些给定接口的新类(也称“动态代理类”)及其实例(对象),代理的是接口(Interfaces),不是类(Class),也不是抽象类。在运行时才知道具体的实现,spring aop就是此原理。
一:写一个接口:
package com.openlab.dao;
public interface UserDao {public int add(int a,int b);
}
接着写一个类实现接口:
package com.openlab.dao.Impl;
import com.openlab.pojo.PeoPle;
import lombok.Data;
import org.springframework.stereotype.Component;
@Component
@Data
public class PeopleDao {public void save(){System.out.println("PeopleDao中的实现类1---save");}public Integer test(int a,int b){System.out.println("PeopleDao实现类执行了------加法运算");return a+b;}
}
测试类,写了一个InvocationHandler内部类:
也可以写一个写一个类实现InvocationHandler接口:
我写的是第一种内部类方式:
package com.openlab;
import com.openlab.dao.Impl.UserDaoImpl;
import com.openlab.dao.UserDao;
import com.openlab.config.Springconfig;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
public class MyTest {public static void main(String[] args) {ApplicationContext context = new AnnotationConfigApplicationContext(Springconfig.class);final UserDaoImpl userDao = new UserDaoImpl();Class[] interfaces = userDao.getClass().getInterfaces();UserDao o = (UserDao) Proxy.newProxyInstance(MyTest.class.getClassLoader(), interfaces, new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("方法执行前:"+method.getName()+"......."+ Arrays.toString(args));Object invokes = method.invoke(userDao,args);System.out.println("方法执行之后");return invokes;}});int add = o.add(3, 5);System.out.println(add);}
}
Proxy.newProxyInstance(ClassLoader loader, Class>[] interfaces, InvocationHandler h)
第一个参数(ClassLoader loader 表示用哪个类的加载器
第二参数Class>[] interfaces 动态类需要实现的接口个数
第三参数InvocationHandler h 动态代理方法在执行时,会调用h里面的invoke方法去执行
返回类型是Object类型,需要强转为我们需要的接口类型;
上面代码中,代理u对象,调用UserDao中的add方法时,自动执行InvocationHandler中的invoke方法。
测试结果:

spring aop
- 连接点:类里面那些方法可以被增强,这些方法称为连接点
- 切入点:实际被增强的方法
- 通知:实际增强的逻辑部分 类型:前置通知 后置通知 环绕通知 异常通知 最终通知
- 切面:动作,把通知应用到切入点过程
通过注解方式
aop注解:
Advice(通知、切面): 某个连接点所采用的处理逻辑,也就是向连接点注入的代码, AOP在特定的切入点上执行的增强处理。
@Before: 标识一个前置增强方法,相当于BeforeAdvice的功能.
@After: final增强,不管是抛出异常或者正常退出都会执行.
@AfterReturning: 后置增强,似于AfterReturningAdvice, 方法正常退出时执行.
@AfterThrowing: 异常抛出增强,相当于ThrowsAdvice.
@Around: 环绕增强,相当于MethodInterceptor.
表达式标签
表达式标签
execution():用于匹配方法执行的连接点
args(): 用于匹配当前执行的方法传入的参数为指定类型的执行方法
this(): 用于匹配当前AOP代理对象类型的执行方法;注意是AOP代理对象的类型匹配,这样就可能包括引入接口也类型匹配;
target(): 用于匹配当前目标对象类型的执行方法;注意是目标对象的类型匹配,这样就不包括引入接口也类型匹配;
within(): 用于匹配指定类型内的方法执行;
@args():于匹配当前执行的方法传入的参数持有指定注解的执行;
@target():用于匹配当前目标对象类型的执行方法,其中目标对象持有指定的注解;
@within():用于匹配所以持有指定注解类型内的方法;
@annotation:用于匹配当前执行方法持有指定注解的方法;
PeoPleDaoProxy 类
package com.openlab.dao.proxy;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;@Aspect
@Component
public class PeoPleDaoProxy {@Pointcut(value="execution(* com.openlab.*.*.*(..))")//Pointcut(切入点):// JoinPoint的集合,是程序中需要注入Advice的位置的集合,指明Advice要在什么样的条件下才能被触发,在程序中主要体现为书写切入点表达式。public void Poin(){}@Before(value = "execution(* com.openlab.dao.Impl.PeopleDao.*())") //前置通知public void before(){System.out.println("方法执行前");}@After(value = "execution(* com.openlab.dao.Impl.PeopleDao.*())") //后置通知public void after(){System.out.println("方法执行后");}@AfterReturning(value = "execution(* com.openlab.dao.Impl.PeopleDao.*())")public void afterReturning(){System.out.println("最终执行");}@AfterThrowing(value="Poin()")//异常通知public void aferthrow(){System.out.println("出异常了");}@Around(value = "execution(* com.openlab.dao.Impl.PeopleDao.*())") //环绕通知public void around(ProceedingJoinPoint joinPoint) throws Throwable {System.out.println("执行之前环绕");joinPoint.proceed();System.out.println("执行之后环绕");}
}
调用类:
package com.openlab.dao.Impl;import com.openlab.pojo.PeoPle;
import lombok.Data;
import org.springframework.stereotype.Component;@Component
@Data
public class PeopleDao {public void save(){System.out.println("PeopleDao中的实现类1---save");}public Integer Update(PeoPle people){System.out.println("PeopleDao实现类执行了:"+people);return 10;}public Integer test(int a,int b){System.out.println("PeopleDao实现类执行了------加法运算");try{int month=1/0;}catch(Throwable e){System.err.println("方法出错");}finally {System.out.println("方法的finally");}return a+b;}
}
applicationContext.xml 配置
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttps://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"><context:component-scan base-package="com.openlab"/><aop:aspectj-autoproxy /> //重点beans>
测试类
package com.openlab;
import com.openlab.dao.Impl.PeopleDao;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ProxyTest {@Testpublic void test01(){ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");PeopleDao peopleDao = context.getBean(PeopleDao.class);peopleDao.save();Integer test = peopleDao.test(5, 7);System.out.println(test);}
}
测试结果:

注解方式类型的顺序:
环绕前通知 前置通知 (运行方法) 异常通知 最终通知 后置通知 环绕后通知
xml配置方式:
所以我们只需要把aop:aspectj-autoproxy注释掉,切面类的注释方式就失效了。所以我就只修改了xml的配置:
<context:component-scan base-package="com.openlab" >context:component-scan><bean id="PeoPleDaoProxy" class="com.openlab.dao.proxy.PeoPleDaoProxy">bean><aop:config><aop:pointcut expression="execution(* com.openlab.*.*.*(..))" id="poin"/><aop:aspect ref="PeoPleDaoProxy"><aop:before method="before" pointcut-ref="poin">aop:before><aop:after method="after" pointcut-ref="poin">aop:after><aop:after-returning method="afterReturning" pointcut-ref="poin"/><aop:after-throwing method="aferthrow" pointcut-ref="poin"/><aop:around method="around" pointcut-ref="poin"/>aop:aspect>aop:config>
我们发现xml配置类型的顺序和注解方式顺序不一样;最后发现是xml中。
Spring-JDBC
首先:pom.xml引入依赖
<dependency><groupId>org.springframeworkgroupId><artifactId>spring-jdbcartifactId><version>5.3.5version>dependency>
<dependency><groupId>mysqlgroupId><artifactId>mysql-connector-javaartifactId><version>8.0.26version>dependency>
在准备db.properties
#\u8FDE\u63A5\u8BBE\u7F6E
//com.mysql.jdbc.Driver 是 mysql-connector-java 5中的,
//com.mysql.cj.jdbc.Driver 是 mysql-connector-java 6后的
jdbc.driverClassName=com.mysql.cj.jdbc.Driver//我的mysql数据库是8.26的所以是com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/t1 //jdbc:mysql: 是指JDBC连接方式;localhost: 是指你的本机地址
jdbc.name=root //用户名
jdbc.password=root //密码
创建数据库对应的类

package com.openlab.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Classes {private int id;private String mnane;private int sums;
}
dao包建接口:
package com.openlab.dao;import com.openlab.pojo.Classes;public interface ClassesDao {public int add(Classes role);//添加public int updat(Classes role);//更新public int delete(int roleid);//删除
}
Impl包里创建类实现接口:
package com.openlab.dao.Impl;import com.openlab.dao.ClassesDao;
import com.openlab.pojo.Classes;
import org.springframework.jdbc.core.JdbcTemplate;public class ClassDaoImpl implements ClassesDao {private JdbcTemplate jdbcTemplate;public JdbcTemplate getJdbcTemplate() {return jdbcTemplate;}public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {this.jdbcTemplate = jdbcTemplate;}@Overridepublic int add(Classes classes) {String sql="insert into class(id,mnane,snums) value(?,?,?)";// 定义数组来存放SQL语句中的参数Object[] obj = new Object[] {classes.getId(),classes.getMnane(),classes.getSums()};// 执行添加操作,返回受SQL语句影响的条数int num = this.jdbcTemplate.update(sql, obj);return num;}@Overridepublic int updat(Classes classes) {String sql="update into class(id,mnane,snums) value(?,?,?)";// 定义数组来存放SQL语句中的参数Object[] obj = new Object[] {classes.getId(),classes.getMnane(),classes.getSums()};// 执行添加操作,返回受SQL语句影响的条数int num = this.jdbcTemplate.update(sql, obj);return num;}@Overridepublic int delete(int id) {// 定义SQLString sql = "delete from class where id=?";// 执行更新操作,返回受SQL语句影响的条数int num=this.jdbcTemplate.update(sql,id);return num;}
}
xml配置
<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 https://www.springframework.org/schema/context/spring-context.xsd"><context:property-placeholder location="classpath:db.properties">context:property-placeholder><bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource"><property name="driverClassName" value="${jdbc.driverClassName}">property><property name="url" value="${jdbc.url}">property><property name="username" value="${jdbc.name}">property><property name="password" value="${jdbc.password}">property>bean><bean id="jdbcTemplate"class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource">property>bean><bean id="classImpl" class="com.openlab.dao.Impl.ClassDaoImpl"><property name="jdbcTemplate" ref="jdbcTemplate">property>bean>
beans>
测试类:
package com.openlab;import com.openlab.dao.Impl.ClassDaoImpl;
import com.openlab.pojo.Classes;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class Testclass {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("beans2.xml");ClassDaoImpl classimpl = context.getBean("classImpl", ClassDaoImpl.class);Classes lala = new Classes(10, "拉拉", 38);int adds = classimpl.add(lala);if(adds>0) {System.out.println("成功插入"+adds+"条数据!");}else {System.out.println("插入操作执行失败");}}
}
插入结果:


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
