一、要使用注解方式配置 IoC,除了以前引入的基础 jar 包,还须要引入 spring-aop 支持包,以下:html
二、在 applicationContext.xml 中引入 context 约束:java
<?xml version="1.0" encoding="utf-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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"> <!--配置文件约束在 spring-framework-4.2.4.RELEASE\docs\spring-framework-reference\html\xsd-configuration.html 下能够找到--> </beans>
package com.zze.dao; public interface UserDao { void save(); }
package com.zze.dao.impl; import com.zze.dao.UserDao; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; /** * 实例化当前类并将其交给 Spring 管理 * 至关于在配置文件中配置 <bean id="userDao" class="com.zze.dao.impl.UserDaoImpl"/> */ @Component("userDao") public class UserDaoImpl implements UserDao { /* 给属性注入值 */ @Value("张三") private String name; /* 若是提供了 set 方法,则可在 set 方法上加上注解 */ // @Value("张三") // public void setName(String name) { // this.name = name; // } @Override public void save() { System.out.println("from UserDaoImpl.save()" + name); } }
<?xml version="1.0" encoding="utf-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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"> <!--使用 IoC 注解开发,配置注解扫描的包(哪些包下使用了 IoC 注解)--> <context:component-scan base-package="com.zze.dao"/> </beans>
@Test public void test1(){ ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); UserDao userDao = (UserDao) applicationContext.getBean("userDao"); userDao.save(); }
修饰一个类,将这个类实例交给 Spring 管理。web
这个注解有三个衍生注解(功能相同):spring
普通类型的属性注入:数据库
对象类型的属性注入:express
@Autowired @Qualifier("userDao") private UserDao userDao;
@Resource(name = "userDao") private UserDao userDao;
修饰一个类,指定其做用范围。编程
singleton :默认值,Spring 会采用单例模式建立这个对象。session
prototype :多例的。app
request :应用在 web 项目中,Spring 建立这个类对象后,将这个对象存放到 request 范围中。框架
session :应用在 web 项目中,Spring 建立这个类对象后,将这个对象存放的 session 范围中。
globalsession :应用在 web 项目中,必须在 porlet 环境下使用。
XML 方式:结构清晰,维护方便,适用于任意场景。
注解方式:简易开发,当一个类不是本身编写而是由第三方提供时,不可使用。
<?xml version="1.0" encoding="utf-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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"> <!--在没有类注解扫描的状况下,使用属性注入注解。--> <context:annotation-config/> <bean name="userService" class="com.zze.service.impl.UserServiceImpl"/> <bean name="userDao" class="com.zze.dao.impl.UserDaoImpl"/> </beans>
package com.zze.service.impl; import com.zze.dao.UserDao; import com.zze.service.UserService; import javax.annotation.Resource; public class UserServiceImpl implements UserService { @Resource(name = "userDao") private UserDao userDao; @Override public void save() { System.out.println("from UserServiceImpl.save()"); userDao.save(); } }
在软件业,AOP 为 Aspect Oriented Programming 的缩写,意为:面向切面编程,经过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP 是 OOP 的延续,是软件开发中的一个热点,也是 Spring 框架中的一个重要内容,是函数式编程的一种衍生范型。利用 AOP 能够对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度下降,提升程序的可重用性,同时提升了开发的效率。
AOP 思想最先是由 AOP 联盟组织提出,Spring 是目前使用这种思想最好的框架。
Spring 自己有本身的 AOP 实现方式,可是很是繁琐。AspectJ 是一个 AOP 框架,Spring 后期引入了 AspectJ 用做自身 AOP 开发。
Spring中AOP实现原理:
Spring 底层是使用动态代理技术实现 AOP。当被代理类实现了接口,此时就会使用 JDK 动态代理方式生成代理对象。当被代理类未实现接口,此时 Spring 就会使用 Cglib 动态代理方式生成代理对象。
程序执行的某个特定位置:如类开始初始化前、类初始化后、类某个方法调用前、调用后、方法抛出异常后。一个类或一段程序代码拥有一些具备边界性质的特定点,这些点中的特定点就称为“链接点”。Spring 仅支持方法的链接点,即仅能在方法调用前、方法调用后、方法抛出异常时以及方法调用先后这些程序执行点织入加强。链接点由两个信息肯定:第一是用方法表示的程序执行点;第二是用相对点表示的方位。
通俗讲其实就是能够被拦截到的点(方法),增删改查方法均可以被拦截加强,这些方法就能够称为是链接点。
每一个程序类都拥有多个链接点,如一个拥有两个方法的类,这两个方法都是链接点,即链接点是程序类中客观存在的事物。AOP经过“切点”定位特定的链接点。链接点至关于数据库中的记录,而切点至关于查询条件。切点和链接点不是一对一的关系,一个切点能够匹配多个链接点。在Spring中,切点经过org.springframework.aop.Pointcut接口进行描述,它使用类和方法做为链接点的查询条件,Spring AOP的规则解析引擎负责切点所设定的查询条件,找到对应的链接点。其实确切地说,不能称之为查询链接点,由于链接点是方法执行前、执行后等包括方位信息的具体程序执行点,而切点只定位到某个方法上,因此若是但愿定位到具体链接点上,还须要提供方位信息。
通俗讲就是真正被拦截到的点(方法),若是在开发中只对 save 方法进行加强,那么 save 就称为是切入点。
加强是织入到目标类链接点上的一段程序代码,在 Spring 中,加强除用于描述一段程序代码外,还拥有另外一个和链接点相关的信息,这即是执行点的方位。结合执行点方位信息和切点信息,咱们就能够找到特定的链接点。
通俗讲就是方法层面的加强,若是要使用 checkPermission 方法进行权限校验,那么 checkPermission 方法就称为是加强。
加强逻辑的织入目标类。若是没有 AOP,目标业务类须要本身实现全部逻辑,而在 AOP 的帮助下,目标业务类只实现那些非横切逻辑的程序逻辑,而性能监视和事务管理等这些横切逻辑则可使用 AOP 动态织入到特定的链接点上。
通俗讲就是指被加强的类,若是对 UserDao 类进行加强,那么 UserDao 类就是目标对象。
引介是一种特殊的加强,它为类添加一些属性和方法。这样,即便一个业务类本来没有实现某个接口,经过 AOP 的引介功能,咱们能够动态地为该业务类添加接口的实现逻辑,让业务类成为这个接口的实现类。
通俗讲就是类层面的加强。
织入是将加强添加对目标类具体链接点上的过程。AOP 像一台织布机,将目标类、加强或引介经过 AOP 这台织布机完美无缺地编织到一块儿。根据不一样的实现技术,AOP有三种织入的方式:
a、编译期织入,这要求使用特殊的Java编译器。通俗讲就是将通知(Advice)应用到目标对象(Target)的过程。
一个类被 AOP 织入加强后,就产出了一个结果类,它是融合了原类和加强逻辑的代理类。根据不一样的代理方式,代理类既多是和原类具备相同接口的类,也可能就是原类的子类,因此咱们能够采用调用原类相同的方式调用代理类。
通俗讲就是最后返回的代理对象。
切面由切入点和加强(引介)组成,它既包括了横切逻辑的定义,也包括了链接点的定义,Spring AOP 就是负责实施切面的框架,它将切面所定义的横切逻辑织入到切面所指定的链接点中。
通俗讲就是切入点与通知的组合。
一、导包,除了要引入 6 个基础 jar 包外,还需引入以下 jar 包:
二、编写切面类:
package com.zze.aspect; import org.aspectj.lang.ProceedingJoinPoint; /** * 切面类 */ public class MyAspect { public void before() { System.out.println("前置通知"); } public void afterReturning(Object result) { System.out.println("后置通知" + result); } public void around(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("环绕通知前"); joinPoint.proceed(); System.out.println("环绕通知后"); } public void afterThrowing(Throwable ex) { System.out.println("异常抛出通知" + ex); } public void after(){ System.out.println("最终通知"); } }
三、编写目标类:
package com.zze.dao; public interface UserDao { public void save(); public Boolean delete(); public void list(); public void update(); }
package com.zze.dao.impl; import com.zze.dao.UserDao; public class UserDaoImpl implements UserDao { public void save() { System.out.println("保存操做 from com.zze.dao.impl.UserDaoImpl.save()"); } public Boolean delete() { System.out.println("删除操做 from com.zze.dao.impl.UserDaoImpl.delete()"); return true; } public void list() { System.out.println("查询操做 from com.zze.dao.impl.UserDaoImpl.list()"); int i = 1 / 0; } public void update() { System.out.println("修改操做 from com.zze.dao.impl.UserDaoImpl.update()"); } }
四、配置 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 http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!--配置目标对象--> <bean name="userDao" class="com.zze.dao.impl.UserDaoImpl" /> <!--配置切面类,将切面类交给 Spring 管理--> <bean name="myAspect" class="com.zze.aspect.MyAspect"/> <!--经过 AOP 配置对目标类代理--> <aop:config> <!-- 表达式配置使用哪些方法类加强哪些类 语法: [访问修饰符] 方法返回值 包名.类名.方法名(参数) * 表示通配符 参数位置使用 .. 匹配任意参数 --> <aop:pointcut id="pc1" expression="execution(* com.zze.dao.UserDao.save(..))"/> <aop:pointcut id="pc2" expression="execution(* com.zze.dao.UserDao.delete(..))"/> <aop:pointcut id="pc3" expression="execution(* com.zze.dao.UserDao.update(..))"/> <aop:pointcut id="pc4" expression="execution(* com.zze.dao.UserDao.list(..))"/> <!--配置切面--> <aop:aspect ref="myAspect"> <!--前置通知--> <aop:before pointcut-ref="pc1" method="before"/> <!--后置通知--> <aop:after-returning pointcut-ref="pc2" method="afterReturning" returning="result"/> <!--环绕通知--> <aop:around pointcut-ref="pc3" method="around"/> <!--异常抛出通知--> <aop:after-throwing pointcut-ref="pc4" method="afterThrowing" throwing="ex"/> <!--最终通知--> <aop:after pointcut-ref="pc4" method="after"/> </aop:aspect> </aop:config> </beans>
五、测试:
package com.zze.test; import com.zze.dao.UserDao; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import javax.annotation.Resource; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class Test{ @Resource(name = "userDao") private UserDao userDao; @Test public void test() { userDao.save(); userDao.delete(); userDao.update(); userDao.list(); /* 前置通知 保存操做 from com.zze.dao.impl.UserDaoImpl.save() 删除操做 from com.zze.dao.impl.UserDaoImpl.delete() 后置通知true 环绕通知前 修改操做 from com.zze.dao.impl.UserDaoImpl.update() 环绕通知后 查询操做 from com.zze.dao.impl.UserDaoImpl.list() 最终通知 异常抛出通知java.lang.ArithmeticException: / by zero */ } }
这里使用了 Spring 整合 JUnit 测试,须要额外导入 spring-test 包。
一、导包,和 XML 配置 AOP 时相同,以下:
二、编写目标类:
package com.zze.dao; public class UserDao { public void save() { System.out.println("保存操做 from com.zze.dao.impl.UserDao.save()"); } public Boolean delete() { System.out.println("删除操做 from com.zze.dao.impl.UserDao.delete()"); return true; } public void list() { System.out.println("查询操做 from com.zze.dao.impl.UserDao.list()"); int i = 1 / 0; } public void update() { System.out.println("修改操做 from com.zze.dao.impl.UserDao.update()"); } }
三、编写切面类并使用注解配置:
package com.zze.aspect; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; /** * 切面类 */ @Aspect public class MyAspect { /** * 定义一个切入点表达式,在下方可引用 */ @Pointcut("execution(* com.zze.dao.UserDao.list(..))") public void pc1() { } /** * 前置通知 */ @Before(value = "execution(* com.zze.dao.UserDao.save(..))") public void before() { System.out.println("前置通知"); } /** * 后置通知 */ @AfterReturning(value = "execution(* com.zze.dao.UserDao.delete(..))", returning = "result") public void afterReturning(Object result) { System.out.println("后置通知" + result); } /** * 环绕通知 */ @Around(value = "execution(* com.zze.dao.UserDao.update(..))") public void around(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("环绕通知前"); joinPoint.proceed(); System.out.println("环绕通知后"); } /** * 异常抛出通知 */ @AfterThrowing(value = "pc1()", throwing = "ex") public void afterThrowing(Throwable ex) { System.out.println("异常抛出通知" + ex); } /** * 最终通知 */ @After(value = "pc1()") public void after() { System.out.println("最终通知"); } }
四、配置 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 http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!--开启注解 AOP 开发--> <aop:aspectj-autoproxy/> <!--目标类--> <bean name="userDao" class="com.zze.dao.UserDao"/> <!--切面类--> <bean name="myAspect" class="com.zze.aspect.MyAspect"/> </beans>
五、测试:
package com.zze.test; import com.zze.dao.UserDao; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class Demo2 { @Autowired private UserDao userDao; @Test public void test() { userDao.save(); userDao.delete(); userDao.update(); userDao.list(); /* 前置通知 保存操做 from com.zze.dao.impl.UserDao.save() 删除操做 from com.zze.dao.impl.UserDao.delete() 后置通知true 环绕通知前 修改操做 from com.zze.dao.impl.UserDao.update() 环绕通知后 查询操做 from com.zze.dao.impl.UserDao.list() 最终通知 异常抛出通知java.lang.ArithmeticException: / by zero */ } }