Spring---AOP面向切面编程与注解
AOP相关术语
全称:Aspect-OrientedProgramming。
可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力。也是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。对于其他类型的代码,如安全性、异常处理和透明的持续性也是如此。
切面(Aspect):一个关注点的模块化,这个关注点可能会横切多个对象。事务管理是J2EE应用中一个关于横切关 注点的很好的例子。在Spring AOP中,切面可以使用基于模式)或者基于@Aspect注解的方式来实现。
连接点(Joinpoint):在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候。在Spring AOP中,一个连接点总是表示一个方法的执行。
通知(Advice):在切面的某个特定的连接点上执行的动作。其中包括了“around”、“before”和“after”等 不同类型的通知(通知的类型将在后面部分进行讨论)。许多AOP框架(包括Spring)都是以拦截器做通知模型, 并维护一个以连接点为中心的拦截器链。
切入点(Pointcut):匹配连接点的断言。通知和一个切入点表达式关联,并在满足这个切入点的连接点上运行 (例如,当执行某个特定名称的方法时)。切入点表达式如何和连接点匹配是AOP的核心:Spring缺省使用 AspectJ切入点语法。
引入(Introduction):用来给一个类型声明额外的方法或属性(也被称为连接类型声明(inter-type declaration))。Spring允许引入新的接口(以及一个对应的实现)到任何被代理的对象。例如,你可以使用引入 来使一个bean实现IsModified接口,以便简化缓存机制。
目标对象(Target Object): 被一个或者多个切面所通知的对象。也被称做被通知(advised)对象。 既然Spring AOP是通过运行时代理实现的,这个对象永远是一个被代理(proxied)对象。
AOP代理(AOP Proxy):AOP框架创建的对象,用来实现切面契约(例如通知方法执行等等)。在Spring中, AOP代理可以是JDK动态代理或者CGLIB代理。
织入(Weaving):把切面连接到其它的应用程序类型或者对象上,并创建一个被通知的对象。这些可以在编译时 (例如使用AspectJ编译器),类加载时和运行时完成。Spring和其他纯Java AOP框架一样,在运行时完成织入。
AOP通知类型
• 前置通知(Before advice)
• 后置通知(After returning advice)
• 异常通知(After throwing advice)
• 最终通知(After (finally) advice)
• 环绕通知(Around Advice)
AOP Schema
applicationContext.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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- an HTTP Session-scoped bean exposed as a proxy -->
<bean id="userPreferences" class="com.something.UserPreferences" scope="session">
<!-- instructs the container to proxy the surrounding bean -->
<aop:scoped-proxy/>
</bean>
<!-- a singleton-scoped bean injected with a proxy to the above bean -->
<bean id="userService" class="com.something.SimpleUserService">
<!-- a reference to the proxied userPreferences bean -->
<property name="userPreferences" ref="userPreferences"/>
</bean>
</beans>
通知类
需要的jar包:导入pom.xml中
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
<scope>runtime</scope>
</dependency>
applicationContext.xml:
<!--纳入Spring管理-->
<bean id="myAspect" class="com.hisoft.aspect.MyAspect"/>
<!--切面-->
<aop:config>
<aop:aspect ref="myAspect">
<aop:pointcut id="myPointcut" expression="execution(* com.hisoft.dao..*.*(..))"/>
<aop:before method="beforeAdvice" pointcut-ref="myPointcut"/>
<aop:after-returning method="afterAdvice" pointcut-ref="myPointcut"/>
<aop:after-throwing method="exceptionAdvice" pointcut-ref="myPointcut"/>
<aop:after method="finalAdvice" pointcut-ref="myPointcut"/>
</aop:aspect>
</aop:config>
配置xml:
<!--环绕通知-->
<bean id="aroundAdvice" class="com.hisoft.aspect.AroundAdvice"/>
<aop:config>
<aop:aspect ref="aroundAdvice">
<aop:pointcut id="myPointcut" expression="execution(* com.hisoft.dao..*.*(..))"/>
<aop:around method="aroundAdvice" pointcut-ref="myPointcut"/>
</aop:aspect>
</aop:config>
MyAspect类:
package com.hisoft.aspect;
public class MyAspect {
private long startTime;
private long endTime;
public void beforeAdvice(){
startTime = System.currentTimeMillis(); //起始时间
System.out.println(startTime);
System.out.println("前置通知......");
}
public void afterAdvice(){
endTime = System.currentTimeMillis(); //结束时间
System.out.println(endTime);
System.out.println("后置通知......");
}
public void exceptionAdvice(){
System.out.println("异常通知......");
}
public void finalAdvice(){
System.out.println(endTime - startTime);
System.out.println("最后通知......");
}
}
环绕通知(Around Advice)
需要的jar包:导入pom.xml中
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.6</version>
<scope>runtime</scope>
</dependency>
AroundAdvice类:
package com.hisoft.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
public class AroundAdvice {
public Object aroundAdvice(ProceedingJoinPoint pjp){
Object obj = null;
try {
long startTime = System.currentTimeMillis();
System.out.println("前置通知。。。。");
obj = pjp.proceed();
long endTime = System.currentTimeMillis();
System.out.println("后置通知。。。。");
System.out.println(endTime - startTime);
} catch (Throwable throwable) {
System.out.println("异常通知。。。。");
throwable.printStackTrace(); //打印异常
}finally {
System.out.println("最终通知。。。。");
}
return obj;
}
}
AspectJ中的Execution表达式
<aop:pointcut id=“myPointcut” expression=“execution(* com.hisoft.dao….(…))”/>
表达式分为五部分:
1、execution():表达式主体;
2、第一个*号:表示返回类型, *表示所有类型;
3、包名:表示需要拦截的包名,后面两个句点表示当前包和当前包的所有子包,子孙包下的所有方法;
4、第二个*号:表示类名,*表示所有的类;
5、*(..):最后这个*号表示方法名,*表示所有的方法,后面括弧里面表示方法的参数,
两个句点表示任何参数;
Annotation注解
Bean的注解:
@Component 组件
@Service 服务
@Repository 仓库
pom.xml配置
<!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
<!--spring beans-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<!--spring core-->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<!--spring context-->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<!--spring-aop -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.6</version>
<scope>runtime</scope>
</dependency>
application.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.hisoft"/>
<context:annotation-config/>
</beans>
UserDaoImpl类
package com.hisoft.dao.Impl;
import com.hisoft.dao.UserDao;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Repository;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@Repository
@Lazy(value = true) //懒加载
@Scope(value = "singleton") //单例singleton 多例 prototype
public class UserDaoImpl implements UserDao {
public UserDaoImpl(){
System.out.println("create.......");
}
public void save(){
System.out.println("userDaoImpl save.........");
}
//初始化
@PostConstruct
public void init(){
System.out.println("init.......");
}
//销毁 容器关闭时执行
@PreDestroy
public void destroy(){
System.out.println("destroy......");
}
}
@Service
public class UserServiceImpl implements UserService {
}
测试类
import com.hisoft.dao.Impl.UserDaoImpl;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
UserDaoImpl userDaoImpl = (UserDaoImpl) context.getBean("userDaoImpl");
// userDaoImpl.save();
context.close();//关闭
// context.registerShutdownHook();
}
}
JSR 330 Standard Annotation
IOC Annotation:
@Autowired
@Inject
@Resource
pom.xml
需要导入javax.inject.jar(源自JavaEE6)
<!--javax.inject -->
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
UserServiceImpl
package com.hisoft.service.Impl;
import com.hisoft.dao.UserDao;
import com.hisoft.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.inject.Inject;
@Service
public class UserServiceImpl implements UserService {
// @Autowired
@Resource
// @Inject
private UserDao userDao;
public void save(){
userDao.save();
}
// @Autowired
// public void setUserDao(UserDao userDao) {
// this.userDao = userDao;
// }
}
Test
public class Test {
public static void main(String[] args) {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
// UserDaoImpl userDaoImpl = (UserDaoImpl) context.getBean("userDaoImpl");
// userDaoImpl.save();
UserServiceImpl userServiceImpl = (UserServiceImpl) context.getBean("userServiceImpl");
userServiceImpl.save();
context.close();//关闭
// context.registerShutdownHook();
}
}
AOP Annotation
pom.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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--开启基于注解的Bean管理 依赖注入-->
<context:component-scan base-package="com.hisoft"/>
<aop:aspectj-autoproxy/> <!--自动注入-->
</beans>
MyAspect
package com.hisoft.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;
import javax.inject.Named;
@Aspect
@Component //纳入容器管理
public class MyAspect {
@Pointcut("execution(* com.hisoft.dao..*.*(..))")
public void pointcut(){
}
//环绕
/* @Around("pointcut()")
public Object aroundAdvice(ProceedingJoinPoint pjp){
Object obj = null;
try {
System.out.println("前置通知。。。");
obj = pjp.proceed();
System.out.println("后置通知。。。");
} catch (Throwable throwable) {
System.out.println("异常通知");
throwable.printStackTrace();
}finally {
System.out.println("最终通知。。。");
}
return obj;
}*/
@Before(value = "pointcut()")
public void beforeAdvice(){
System.out.println("前置通知。。。。。");
}
@AfterReturning(value = "pointcut()")
public void afterAdvice(){
System.out.println("后置通知。。。。");
}
@AfterThrowing("pointcut()")
public void ExceptionAdvice(){
System.out.println("异常通知。。。。");
}
@After("pointcut()")
public void finalAdvice(){
System.out.println("最终通知。。。。");
}
}
Test
import com.hisoft.dao.Impl.UserDaoImpl;
import com.hisoft.service.Impl.UserServiceImpl;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
// UserDaoImpl userDaoImpl = (UserDaoImpl) context.getBean("userDaoImpl");
// userDaoImpl.save();
UserServiceImpl userServiceImpl = (UserServiceImpl) context.getBean("userServiceImpl");
userServiceImpl.save();
context.close();//关闭
// context.registerShutdownHook();
}
}