Spring 是轻量级的开源的 JavaEE 框架,
Spring有两个核心部分IOC 和 Aop
- IOC(Inversion of Control):控制反转,把创建物件程序交给 Spring 进行管理
- Aop(Aspect Oriented Programming):面向切面编程,不修改源代码进行功能增强
Spring特点:
- 方便解耦,简化开发
- Aop 编程支持
- 方便程序测验
- 方便和其他框架进行整合
- 方便进行事务操作
- 降低 API 开发难度
本篇介绍主要介绍AOP
底层原理
AOP的底层使用动态代理,动态代理有两种情况,一种为有界面的情况(使用JDK动态代理),一种为没有界面的情况(使用CGLIB动态代理)下面介绍的是有界面的情况
使用JDK动态代理:
关键方法newProxyInstance(ClassLoader loader, class<?>[] interfaces, InvocationHandler h)
该方法回传指定界面的代理实体,loader
:用户定义代理类的类加载器;interfaces
:要实作的代理类的界面串列;h
:实作InvocationHandler的类,在重写的invoke方法中加入自己增强的代码部分,
使用Proxy类创建UserDao界面代理物件的代码如下,UserDao为自己定义的一个界面,界面中有一个add方法,UserDaoImpl为界面实作类,
public class JDKProxy {
public static void main(String[] args) {
Class[] interfaces = {UserDao.class};
UserDaoImpl userDaoImpl = new UserDaoImpl();
//创建界面实作类代理物件
UserDao dao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDaoImpl));
//测验
dao.add(1, 2);
}
}
//创建代理物件
class UserDaoProxy implements InvocationHandler{
private Object object;
//有参构造器传递物件
public UserDaoProxy(Object object){
this.object = object;
}
//写增强的逻辑,在与其关联的代理实体上呼叫方法时,invoke方法就会被呼叫
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//原方法之前执行代码
System.out.println("原方法之前执行..."+"执行的方法为:"+ method.getName()+"...传递的自变量为:"+ Arrays.toString(args));
//原方法
Object res = method.invoke(object, args);
//原方法之后执行代码
System.out.println("原方法之后执行...");
return res;
}
}
运行结果如下:
自己的白话总结:创建InvocationHandler
界面的实作类并重写invoke
方法,在invoke
方法中添加自己的代码增强部分,呼叫newProxyInstance
回传代理实体并向上转型为界面,当我们呼叫界面中的方法时,就呼叫了invoke
方法,从而实作了代码的功能增强,如有错误请指正,
AOP操作实作
Spring 框架一般都是基于 AspectJ 实作 AOP 操作,AspectJ 不是 Spring 组成部分,它是独立的 AOP 框架,一般把 AspectJ 和 Spirng 框架一起使用,进行 AOP 操作,
基于 AspectJ 实作 AOP 操作有两种方式:
- 基于xml组态档实作
- 基于注解方式实作(常用)
相关术语与切入点表达式
-
连接点:可以被增强的方法
-
切入点:被增强的方法
-
通知:实际增强的逻辑部分(说人话:自己要添加的代码)
通知的型别:
- 前置通知
- 后置通知
- 环绕通知
- 例外通知
- 最终通知
-
切面:把通知应用到切入点的程序(说人话:把增强的代码应用到原方法中)
切入点表达式:
切入点表达式的作用:知道对哪个类里面的哪个方法进行增强
语法结构: execution([权限修饰符] [回传型别] [类全路径] [方法名称]([自变量串列]) )
相关示例如下:
举例 1:对 com.hnust.spring5.dao.BookDao 类里面的 add 进行增强
execution(* com.hnust.spring5.dao.BookDao.add(..))
举例 2:对 com.hnust.spring5.dao.BookDao 类里面的所有的方法进行增强
execution(* com.hnust.spring5.dao.BookDao.* (..))
举例 3:对 com.hnust.spring5.dao 包里面所有类,类里面所有方法进行增强
execution(* com.hnust.spring5.dao.*.* (..))
基于注解方式实作AOP
汇入相关jar包,以下作为参考
com.springsource.net.sf.cglib-2.2.0.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
commons-logging-1.1.1.jar
druid-1.1.9.jar
spring-aop-5.2.6.RELEASE.jar
spring-aspects-5.2.6.RELEASE.jar
spring-beans-5.2.6.RELEASE.jar
spring-context-5.2.6.RELEASE.jar
spring-core-5.2.6.RELEASE.jar
spring-expression-5.2.6.RELEASE.jar
创建普通类
@Component//该注解实作bean注入
public class User {
public void add(){
System.out.println("add....");
}
}
创建增强类,这里展示前置通知,最终通知,后置通知,例外通知和环绕通知
@Component
@Aspect //生成代理物件
public class UserProxy {
//前置通知
@Before(value = "https://www.cnblogs.com/xuzhuo123/archive/2021/12/21/execution(* com.hnust.spring5.aopanno.User.add(..))")
public void before(){
System.out.println("before....");
}
//最终通知
@After(value = "https://www.cnblogs.com/xuzhuo123/archive/2021/12/21/execution(* com.hnust.spring5.aopanno.User.add(..))")
public void after(){
System.out.println("after...");
}
//后置通知(回传通知)
@AfterReturning(value = "https://www.cnblogs.com/xuzhuo123/archive/2021/12/21/execution(* com.hnust.spring5.aopanno.User.add(..))")
public void afterReturning(){
System.out.println("afterReturning...");
}
//例外通知
@AfterThrowing(value = "https://www.cnblogs.com/xuzhuo123/archive/2021/12/21/execution(* com.hnust.spring5.aopanno.User.add(..))")
public void afterThrowing(){
System.out.println("afterThrowing...");
}
//环绕通知
@Around(value = "https://www.cnblogs.com/xuzhuo123/archive/2021/12/21/execution(* com.hnust.spring5.aopanno.User.add(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint){
System.out.println("环绕之前");
//执行原方法
try {
proceedingJoinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println("环绕之后");
}
}
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"
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
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--开启注解扫描-->
<context:component-scan base-package="com.hnust.spring5"></context:component-scan>
<!--开启Aspectj生成代理物件-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
创建测验类
@Test
public void testAopAnno(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
User user = context.getBean("user", User.class);
user.add();
}
执行结果:
前置通知,在方法执行之前执行;
最终通知,在方法执行之后执行;
后置通知(回传通知),在方法回传结果之后执行;
例外通知,在方法抛出例外之后执行;
环绕通知,围绕着方法执行,
关于最终通知和后置通知可能会有概念上的区别,以自己学的实际为准,
如果有多个增强类对同一个方法进行增强,可以通过添加注解 @Order(数字)
来设定优先级,数字越小,优先级越高,
操作数据库
Spring 框架对 JDBC 进行封装,使用 JdbcTemplate 方便实作对数据库操作
首先引入相关jar包,具体版本根据自己的实际版本为准,以下为参考
com.springsource.net.sf.cglib-2.2.0.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
commons-logging-1.1.1.jar
druid-1.1.9.jar
mysql-connector-java-5.1.7-bin.jar
spring-aop-5.2.6.RELEASE.jar
spring-aspects-5.2.6.RELEASE.jar
spring-beans-5.2.6.RELEASE.jar
spring-context-5.2.6.RELEASE.jar
spring-core-5.2.6.RELEASE.jar
spring-expression-5.2.6.RELEASE.jar
spring-jdbc-5.2.6.RELEASE.jar
spring-orm-5.2.6.RELEASE.jar
spring-tx-5.2.6.RELEASE.jar
配置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"
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
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--开启组件扫描-->
<context:component-scan base-package="com.hnust.spring5"></context:component-scan>
<!--配置数据库连接池 -->
<bean id="dataSource"
destroy-method="close">
<property name="url" value="https://www.cnblogs.com/xuzhuo123/archive/2021/12/21/jdbc:mysql:///user_db" />
<property name="username" value="https://www.cnblogs.com/xuzhuo123/archive/2021/12/21/root" />
<property name="password" value="https://www.cnblogs.com/xuzhuo123/archive/2021/12/21/root" />
<property name="driverClassName" value="https://www.cnblogs.com/xuzhuo123/archive/2021/12/21/com.mysql.jdbc.Driver" />
</bean>
<!--JdbcTemplate物件-->
<bean id="jdbcTemplate" >
<!--注入dataSource-->
<property name="dataSource" ref="dataSource"></property>
</bean>
</beans>
撰写dao层代码,以下示例只展示了dao层的部分实作类,其他的功能大同小异,都学到这里了,service层肯定都会写,我就不再贴出来了,
@Service
public class BookDaoImpl implements BookDao{
//注入JdbcTemplate
@Autowired
private JdbcTemplate jdbcTemplate;
//添加
@Override
public void add(Book book) {
String sql = "insert into t_book values(?, ?, ?)";
Object[] args = {book.getUser_id(), book.getUsername(), book.getUstatus()};
int update = jdbcTemplate.update(sql, args);
System.out.println(update);
}
//修改
@Override
public void updateBook(Book book) {
String sql = "update t_book set username=?, ustatus=? where user_id=?";
Object[] args = {book.getUsername(), book.getUstatus(), book.getUser_id()};
int update = jdbcTemplate.update(sql, args);
System.out.println(update);
}
//洗掉
@Override
public void deleteBook(Integer id) {
String sql = "delete from t_book where user_id=?";
int update = jdbcTemplate.update(sql, id);
System.out.println(update);
}
//查询
@Override
public Book findOne(Integer id) {
String sql = "select * from t_book where user_id=?";
return jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<Book>(Book.class),id);
}
}
测验
public class TestBook {
@Test
public void testJdbcTemplate(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
BookServiceImpl bookServiceImpl = context.getBean("bookServiceImpl", BookServiceImpl.class);
//添加
// bookServiceImpl.addBook(new Book(1,"java", "on"){});
//修改
// bookServiceImpl.updateBook(new Book(1,"c++","off"));
//洗掉
// bookServiceImpl.deleteBook(1);
//查询
// System.out.println(bookServiceImpl.findOne(1));
}
}
0 评论