什么是Aop
AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力。也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。对于其他类型的代码,如安全性、异常处理和透明的持续性也是如此。这种散布在各处的无关的代码被称为横切(cross-cutting)代码,在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。
而AOP技术则恰恰相反,它利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,即方面。所谓“方面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。AOP代表的是一个横向的关系,如果说“对象”是一个空心的圆柱体,其中封装的是对象的属性和行为;那么面向方面编程的方法,就仿佛一把利刃,将这些空心圆柱体剖开,以获得其内部的消息。而剖开的切面,也就是所谓的“方面”了。然后它又以巧夺天功的妙手将这些剖开的切面复原,不留痕迹。
使用“横切”技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理。Aop 的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。正如Avanade公司的高级方案构架师Adam Magee所说,AOP的核心思想就是“将应用程序中的商业逻辑同对其提供支持的通用服务进行分离。”
实现AOP的技术,主要分为两大类:一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码。
AOP相关概念
切面(Aspect):一个关注点的模块化,这个关注点实现可能另外横切多个对象。事务管理是J2EE应用中一个很好的横切关注点例子。方面用Spring的 Advisor或拦截器实现。
连接点(Joinpoint): 程序执行过程中明确的点,如方法的调用或特定的异常被抛出。
切入点(Pointcut): 指定一个通知将被引发的一系列连接点的集合。AOP框架必须允许开发者指定切入点:例如,使用正则表达式。 Spring定义了Pointcut接口,用来组合MethodMatcher和ClassFilter,可以通过名字很清楚的理解, MethodMatcher是用来检查目标类的方法是否可以被应用此通知,而ClassFilter是用来检查Pointcut是否应该应用到目标类上
如execution(* com.cqucc.dao.*.*(..))
第一部分*号表示任意返回值
第二部分*号com.DJX.Dao.*表示在com.DJX.Dao包下的任何类
第三部分*号表示任何类下的任何方法
第四部分(..)表示任意参数个数
通知(Advice): 在特定的连接点,AOP框架执行的动作。各种类型的通知包括“around”、“before”和“throws”通知。通知类型将在下面讨论。许多AOP框架包括Spring都是以拦截器做通知模型,维护一个“围绕”连接点的拦截器链。Spring中定义了四个advice: BeforeAdvice, AfterAdvice, ThrowAdvice和DynamicIntroductionAdvice
目标对象(Target ): 包含连接点的对象。也被称作被通知或被代理对象。POJO
织入(Weaving): 组装方面来创建一个被通知对象。这可以在编译时完成(例如使用AspectJ编译器),也可以在运行时完成。Spring和其他纯Java AOP框架一样,在运行时完成织入。
AOP实现方式
1.注解实现
先要对xml的文件进行设置扫描基础包,同时要设置 <aop:aspectj-autoproxy>否则注解不产生效果
<context:component-scan base-package="com.cqucc" />
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
创建类,书写里面的方法并交给Spring管理
import com.cqucc.pojo.User;
import org.springframework.stereotype.Repository;
@Repository
public class UserDao {
public void save(){
System.out.println("userdao中实现了1的save");
}
public void update(User user){
System.out.println("dao中实现了1的" + user);
try {
System.out.println(1/0);
}catch (Exception e){
System.out.println("异常了");
}
}
}
创建增强类(增强逻辑)在增强类里面,创建方法,让不同方法代表不同通知类型
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class UserDaoProxy1 {
@Before(value = "execution(* com.cqucc.dao.UserDao.*(..))")
public void before(){
System.out.println("方法执行之前");
}
@After(value = "execution(* com.cqucc.dao.UserDao.*(..))")
public void after(){
System.out.println("在方法执行之后");
}
@AfterReturning(value = "execution(* com.cqucc.dao.UserDao.*(..))")
public void afterReturning(){
System.out.println("最终通知");
}
@AfterThrowing(value = "execution(* com.cqucc.dao.UserDao.*(..))")
public void afterthrow(){
System.out.println("异常通知");
}
@Around(value = "execution(* com.cqucc.dao.UserDao.*(..))")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕之前");
joinPoint.proceed();
System.out.println("环绕之后");
}
}
书写测试
@Test
public void Test1(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserDao bean = context.getBean(UserDao.class);
bean.update();
}
测试结果
2. 书写Pointcut一个方法对上述代码简化
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class UserDaoProxy1 {
@Pointcut(value = "execution(* com.cqucc.dao.UserDao.*(..))")
public void point(){
}
@Before(value = "point()")
public void before(){
System.out.println("方法执行之前");
}
@After(value = "point()")
public void after(){
System.out.println("在方法执行之后");
}
@AfterReturning(value = "point()")
public void afterReturning(){
System.out.println("最终通知");
}
@AfterThrowing(value = "point()")
public void afterthrow(){
System.out.println("异常通知");
}
@Around(value = "point()")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕之前");
joinPoint.proceed();
System.out.println("环绕之后");
}
}
测试方法同上,结果如下
3.通过配置文件实现
配置beans.xml
<?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"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p"
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-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd">
<context:component-scan base-package="com.cqucc" />
<bean class="com.cqucc.dao.proxy.UserDaoProxy" id="userDaoProxy"></bean>
<aop:config>
<aop:pointcut id="point" expression="execution(* com.cqucc.dao.UserDao.*(..))"/>
<aop:aspect ref="userDaoProxy">
<aop:before method="before" pointcut-ref="point"></aop:before>
<aop:after method="after" pointcut-ref="point"></aop:after>
<aop:after-throwing method="afterthrow" pointcut-ref="point"></aop:after-throwing>
<aop:after-returning method="afterReturning" pointcut-ref="point"></aop:after-returning>
<aop:around method="around" pointcut-ref="point"></aop:around>
</aop:aspect>
</aop:config>
</beans>
配置了xml文件,增强类就不需要注释了
package com.cqucc.dao.proxy;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
public class UserDaoProxy {
public void point(){
}
public void before(){
System.out.println("方法执行之前");
}
public void after(){
System.out.println("在方法执行之后");
}
public void afterReturning(){
System.out.println("最终通知");
}
public void afterthrow(){
System.out.println("异常通知");
}
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕之前");
joinPoint.proceed();
System.out.println("环绕之后");
}
}
测试结果
Spring整合jdbc
1.配置maven仓库
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.9</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-tx -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.3.8</version>
</dependency>
2.添加数据库配置文件
3.使用xml文件对数据库引入
<?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"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p"
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-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd">
<context:component-scan base-package="com.cqucc"></context:component-scan>
<context:property-placeholder location="classpath:db.properties"></context:property-placeholder>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
</beans>
4.创建Cities实体类
package com.cqucc.pojo;
public class Cities {
private int cid;
private String cname;
private int pid;
public Cities() {
}
public Cities(String cname, Integer pid) {
this.cname = cname;
this.pid = pid;
}
public Cities(Integer cid, String cname, Integer pid) {
this.cid = cid;
this.cname = cname;
this.pid = pid;
}
public Integer getCid() {
return cid;
}
public void setCid(Integer cid) {
this.cid = cid;
}
public String getCname() {
return cname;
}
public void setCname(String cname) {
this.cname = cname;
}
public Integer getPid() {
return pid;
}
public void setPid(Integer pid) {
this.pid = pid;
}
@Override
public String toString() {
return "Cities{" +
"cid=" + cid +
", cname='" + cname + '\'' +
", pid=" + pid +
'}';
}
}
对数据库进行基本操作
1. 添加方法
@Repository
public class CitiesDao {
@Autowired//自动注入
private JdbcTemplate jdbcTemplate;
public int insert(Cities cities){
return jdbcTemplate.update("insert into cities values(null,?,?)"
,cities.getCname(),cities.getPid());
}
}
测试方法
@Test
public void Test2(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans3.xml");
CitiesDao bean = context.getBean(CitiesDao.class);
System.out.println(bean.insert(new Cities("重庆",0)));;
}
插入数据前数据库
添加数据后数据库
2.删除方法
import com.cqucc.pojo.Cities;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public class CitiesDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public int delete(int cid){
return jdbcTemplate.update("delete from cities where cid=?",cid);
}
}
测试方法
@Test
public void Test4(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans3.xml");
CitiesDao bean = context.getBean(CitiesDao.class);
bean.delete(23);
}
删除数据后数据库
3.批量查询数据
import com.cqucc.pojo.Cities;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public class CitiesDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public List<Cities> selectAll(){
return jdbcTemplate.query("select * from cities where pidlike ?",new BeanPropertyRowMapper<Cities>(Cities.class),1);
}
}
测试方法
@Test
public void Test5(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans3.xml");
CitiesDao bean = context.getBean(CitiesDao.class);
List<Cities> cities = bean.selectAll();
System.out.println(cities.size());
for (Cities c:cities){
System.out.println(c);
}
}
测试结果
4.批量插入数据
import com.cqucc.pojo.Cities;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public class CitiesDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public int[] inserts(List<Object[]> objects){
return jdbcTemplate.batchUpdate("insert into cities values(null,?,?)",objects);
}
}
测试方法
@Test
public void Test7(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans3.xml");
CitiesDao bean = context.getBean(CitiesDao.class);
List<Object[]> list = new ArrayList<>();
Object[] c1 = {"重庆",9};
Object[] c2 = {"重庆1",98};
Object[] c3 = {"重庆2",98};
Object[] c4 = {"重庆3",98};
list.add(c1);
list.add(c2);
list.add(c3);
list.add(c4);
bean.inserts(list);
}
测试结果
5.批量删除数据
public int[] delete(List<Object[]> objects){
return jdbcTemplate.batchUpdate("delete from cities where pid=?",objects);
}
测试方法
@Test
public void Test8(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans3.xml");
CitiesDao bean = context.getBean(CitiesDao.class);
List<Object[]> list = new ArrayList<>();
Object[] c1 = {9};
Object[] c2 = {98};
Object[] c3 = {98};
Object[] c4 = {98};
list.add(c1);
list.add(c2);
list.add(c3);
list.add(c4);
bean.delete(list);
}
测试结果