一、概述
1. Spring是一个开源框架,其目的是为了解决企业应用开发的复杂性.
2. Spring功能:使用基本的JavaBean代替EJB,并提供更多的企业应用功能.
3. 简单说,Spring是一个轻量级的控制反转(IOC)和面向切面(AOP)的容器框架.
二、Spring的jar包和配置文件
1.Spring的jar包
(1)spring的核心类库在spring文档的dist下.
(2)引入的第三方类库在spring文档的lib下.
(3)常用第三方类库
* 如果使用了切面编程(AOP),需要 lib/aspectj/aspectjweaver.jar和aspectjrt.jar
lib/cglib/cglib-nodep-2.1_3.jar
* 如果使用了@Resource/@PostConstruct/@PreDestroy等注解,需要
lib/j2ee/common-annotations.jar
2.Spring的配置文件
默认是applicationContext.xml文件.
但实际工程中,一般建立多个xml文件,在applicationContext.xml中引入.
三、Spring的基本功能
1.SpringIOC
* spring的控制反转:把对象的创建、初始化、销毁等工作交给spring容器来做,由spring容器控制对象的生命周期.
* spring容器的启动:
(1)在类路径下寻找配置文件来实例化容器(常用):
ApplicationContext ac = new ClassPathXmlApplicationContext(new String[]{"beans.xml"});
这种方式需要将spring配置文件放到当前项目的classpath路径下.
(2)在文件系统路径下寻找配置文件来实例化容器:
ApplicationContext ac = new FileSystemXmlApplicationContext(new String[]{"d:\\beans.xml"});
* 配置文件可以有多个,通过String数组传入.
2.别名
* 使用别名可以达到,在一个地方命名,多个地方使用不同名字的效果.
<beans>
<alias name="person" alias="p"/>
<bean name="person" class="com.liu.domain.Person"/>
</beans>
3.Spring容器内部对象的创建
(1)使用类构造器实例化(默认是无参数的)
<bean id="personService" class="com.liu.bean.impl.PersonServiceImpl"/>
(2)使用静态工厂方法实例化(简单工厂模式)
<bean id="personService" class="com.liu.factory.PersonServiceFactory" factory-method="createPersonService"/>
工厂类:
public class PersonServiceFactory {
public static PersonService createPersonService(){
return new PersonServiceImpl();
}
}
(3)注意,初始化bean时机
* Spring默认在启动时将所有singleton bean提前进行实例化.即作为初始化的一部分.
* ApplicationContext会自动创建并配置所有的singleton bean.
* Lazy-init="false"时,spring容器将在启动的时候报错(可以及时发现错误)
* Lazy-init="true"时,spring容器将在调用该类的时候出错.
4.Bean的作用域(scope属性)
(1)singleton(默认值)
* 在每个spring IoC容器中,一个bean定义只有一个对象实例,即是单例的.
* 默认情况下Bean节点的lazy-init为false,即容器启动就初始化bean,如果想延迟,可改为true
* 如果相对所有bean都延迟初始化,可以在根节点Beans设置default-lazy-init="true"
例如:<beans default-lazy-init="true"..>
(2)prototype
* 允许bean可以被多次实例化(使用一次就创建一个实例).
* spring不能对prototype bean的整个生命周期负责,这就意味着清楚prototype作用域的对象
并释放任何prototype bean所持有的昂贵资源都是客户端的责任
(3)Request
在一次Http请求中,一个bean定义对应一个实例;
即每次Http请求将会有各自的bean实例,它们依据某个bean定义创建而成.
该作用域仅在基于web的Spring ApplicationContext情形下有效.
(4)Session
在一个Http Session中,一个bean定义对应一个实例,该作用域仅在基于web的Spring ApplicationContext情形下有效.
(5)Global session
再一个全局的Http Session中,一个bean定义对应一个实例.
典型情况下,仅在使用portlet context的时候有效.
该作用域仅在基于web的Spring ApplicationContext情形下有效.
(6)指定Bean的初始化方法和销毁方法
* Spring初始化bean或销毁bean时,有时需要作一些处理工作,因此spring可以在创建和拆卸bean的时候调用bean的两个生命周期方.
<bean id=“foo” class=“...Foo”
init-method=“setup”
destory-method=“teardown”/>
* 当foo被载入到Spring容器中时调用init-method方法.当foo从容器中删除时调用destory-method(scope = singleton有效)
5.依赖注入(DI)
(1)使用构造器注入
* 通过xml的方式注入:
A:通过参数的顺序:
<constructor-arg index="0">
<value>张三</value>
</constructor-arg>
<constructor-arg index="1">
<value>56</value>
</constructor-arg>
B:通过参数的类型:
<constructor-arg type="java.lang.Integer">
<value>56</value>
</constructor-arg>
<constructor-arg type="java.lang.String">
<value>张三</value>
</constructor>
(2)使用属性setting方法进行注入
* 通过xml的方式注入:
A:简单Bean的注入:
简单Bean包括:包装类型和String
<bean id="personService" class="com.liu.service.impl.PersonServiceImpl">
<!-- 基本类型,String类型 -->
<property name="age" value="20"/>
<property name="name" value="张三"/>
</bean>
B:引用其它Bean
<bean id="person" class="com.itcast.bean.Person" />
<bean id="personService" class="com.itcast.bean.impl.PersonServiceImpl">
<property name="person" ref="person" />
</bean>
(3)装配list集合
<property name="lists">
<list>
<value>list1</value>
<value>list2</value>
</list>
</property>
(4)装配set集合
<property name="sets">
<set>
<value>set1</value>
<value>set2</value>
</set>
</property>
(5)装配map
<property name="maps">
<map>
<entry key="01">
<value>map01</value>
</entry>
<entry key="02">
<value>map02</value>
</entry>
</map>
</property>
(6)装配Properties
<property name="props">
<props>
<prop key="01">prop1</prop>
<prop key="02">prop2</prop>
</props>
</property>
6.注解注入
(1)步骤
A.在配置文件中,引入context命名空间(星号的)
<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-2.5.xsd
***** http://www.springframework.org/schema/context
***** http://www.springframework.org/schema/context/spring-context-2.5.xsd">
B.在配置文件中加入context:annotation-config标签
<context:annotation-config/>
此配置隐式注册了多个对注释进行解析处理的处理器.
AutowiredAnnotationBeanPostProcessor,
CommonAnnotationBeanPostProcessor,
PersistenceAnnotationBeanPostProcessor,
RequiredAnnotationBeanPostProcessor
注:@Resource注解在spring文档的lib\j2ee\common-annotations.jar
(2)@Autowired
* @Autowired与@Resource区别:
@Autowired默认按类型装配
@Resource默认按名称装配,当找不到与名称匹配的bean时,才会按类型装配.
* @Autowired默认情况下要求依赖对象必须存在,如果允许为null值,可设置它required属性为false
@Autowired(required=false)
private PersonDao personDao; //用于字段上
@Autowired(required=false)
public void setPersonDao(PersonDao personDao){ //用于属性set方法上
this.personDao = personDao;
}
(3)@Qualifier
如果向按名称装配,可以结合@Qualifier注解一起使用.
@Autowired@Qualifier("personDao")
private PersonDao personDao; //用于字段上
@Autowired
public void setPersonDao(@Qualifier("personDao")PersonDao personDao){
this.personDao = personDao;
}
(4)@Resource
* 它也可标注在字段或属性的setter方法上.
* 如果没有指定name属性,会先按照名称寻找依赖对象,如果找不到,会退回到按类型装配,而指定了name属性,则只能按名称装配.
(5)@PostConstruct和@PreDestroy
@PostConstruct:指定bean的初始化方法.
@PreDestroy:指定bean的销毁方法.
7.扫描注入
在一个稍大的项目中,通常会有上百个组件,如果这些组件采用xml的bean定义来配置,显然会增加配置文件的体积,查找及维护起来也不太方便.
spring2.5为我们引入了组件自动扫描机制,它可以在类路径底下寻找标注了@Component、@Service、
@Controller、@Repository注解的类,并把这些类纳入进spring容器中管理.
(1) 步骤
* 引入context命名空间,
和注解注入引入的命名空间是一样的.
* 在配置文件中添加context:component-scan标签
<context:component-scan base-package="com.liu"/>
其中base-package为需要扫描的包(包含子包)
(2)功能
@Service 用于标注业务层组件
@Controller 用于标注控制层组件(如struts中的action)
@Repository 用于标注数据访问组件,即DAO组件
@Component 泛指组件,当组件不好归类时,可以用这个注解标注.
8.spring中的继承
Person类:
public class Person{
private String sex;
//..setter,getter方法略
}
student类:
public class Student extends Person{
..
}
配置文件:
<bean id="person" class="com.liu.Person">
<property name="sex">
<value>man</value>
</property>
</bean>
<bean id="student" class="com.liu.Student" parent="person"/>
配置文件中,parent属性为student在容器中继承person,如果去掉person是不行的.
四、面向切面编程
1.代理模式
(1)JDK动态代理
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
- import java.lang.reflect.Proxy;
- public class JDKProxy implements InvocationHandler {
- private Object targetObject; //代理的目标对象
- public Object createProxyInstance(Object targetObject) {
- this.targetObject = targetObject;
- //第一个参数设置代码使用的类加载器,一般采用跟目标类相同的类加载器
- //第二个参数设置代理类实现的接口跟目标类使用相同的接口
- //第三个参数设置回调对象,当代理对象的方法被调用时,会调用该参数指定对象的invoke方法
- return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
- targetObject.getClass().getInterfaces(), this);
- }
- @Override
- public Object invoke(Object proxy, Method method, Object[] args)
- throws Throwable {
- System.out.println("代理类实例" + proxy.getClass());
- System.out.println("方法名称" + method.getName());
- if(args!=null && args.length>0) { //方法的参数值
- for(int i=0; i<args.length; i++) {
- System.out.println("方法参数值" + args[i].toString());
- }
- Object returnvalue = null; //定义方法的返回值,没有返回值时是null
- returnvalue = method.invoke(this.targetObject, args);//调用目标对象的方法
- System.out.println("方法的返回值" + returnvalue);
- return returnvalue;
- }
- return null;
- }
- }
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JDKProxy implements InvocationHandler {
private Object targetObject; //代理的目标对象
public Object createProxyInstance(Object targetObject) {
this.targetObject = targetObject;
//第一个参数设置代码使用的类加载器,一般采用跟目标类相同的类加载器
//第二个参数设置代理类实现的接口跟目标类使用相同的接口
//第三个参数设置回调对象,当代理对象的方法被调用时,会调用该参数指定对象的invoke方法
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("代理类实例" + proxy.getClass());
System.out.println("方法名称" + method.getName());
if(args!=null && args.length>0) { //方法的参数值
for(int i=0; i<args.length; i++) {
System.out.println("方法参数值" + args[i].toString());
}
Object returnvalue = null; //定义方法的返回值,没有返回值时是null
returnvalue = method.invoke(this.targetObject, args);//调用目标对象的方法
System.out.println("方法的返回值" + returnvalue);
return returnvalue;
}
return null;
}
}
总结:jdk动态代理必须具备四个条件:目标接口、目标类、拦截器、代理类
* 因为利用JDKProxy生成的代理类实现了接口,所以目标类中所有的方法在代理类中都有.
* 利用JDKProxy方式必须有接口的存在
* invoke方法中的三个参数可以访问目标类的被调用方法的API、被调用方法的参数、被调用方法的返回类型.
(2)CGLIB做代理
* 用CGlib生成代理类是目标类的子类
* 用CGlib生成代理类不需要接口
* 用CGlib生成的代理类重写了父类的各个方法
* 拦截器中的intercept方法内容正好就是代理类中的方法体
- //代码示例:需要添加cglib的jar包,可以在spring文档的lib下找到
- import java.lang.reflect.Method;
- import net.sf.cglib.proxy.Enhancer;
- import net.sf.cglib.proxy.MethodInterceptor;
- import net.sf.cglib.proxy.MethodProxy;
- public class CglibProxy implements MethodInterceptor{
- private Object targetObject; //代理的目标对象
- //创建目标对象的代理对象
- public Object createProxyInstance(Object targetObject) {
- this.targetObject = targetObject;
- Enhancer enhancer = new Enhancer(); //该类用于生成代理对象
- enhancer.setSuperclass(this.targetObject.getClass()); //设置父类
- enhancer.setCallback(this); //设置回调对象为本身
- return enhancer.create(); //创建代理对象
- }
- /* obj 目标对象代理类的实例
- * method 代理实例上调用父类方法的Method实例
- * args 传入到代理实例上方法参数值的对象数组
- * methodProxy 使用它调用父类的方法
- */
- @Override
- public Object intercept(Object obj, Method method, Object[] args,
- MethodProxy methodProxy) throws Throwable {
- System.out.println("代理类" + obj.getClass());
- System.out.println("方法名称" + method.getName());
- if(args!=null && args.length>0) {//方法的参数值
- for(int i=0; i<args.length; i++) {
- System.out.println("方法参数" + args[i]);
- }
- Object returnvalue = null;//方法的返回值,无返回类型时,为null
- returnvalue = methodProxy.invoke(this.targetObject, args);//调用目标对象的方法
- System.out.println("方法的返回值" + returnvalue);
- return returnvalue;
- }
- return null;
- }
- }
//代码示例:需要添加cglib的jar包,可以在spring文档的lib下找到
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class CglibProxy implements MethodInterceptor{
private Object targetObject; //代理的目标对象
//创建目标对象的代理对象
public Object createProxyInstance(Object targetObject) {
this.targetObject = targetObject;
Enhancer enhancer = new Enhancer(); //该类用于生成代理对象
enhancer.setSuperclass(this.targetObject.getClass()); //设置父类
enhancer.setCallback(this); //设置回调对象为本身
return enhancer.create(); //创建代理对象
}
/* obj 目标对象代理类的实例
* method 代理实例上调用父类方法的Method实例
* args 传入到代理实例上方法参数值的对象数组
* methodProxy 使用它调用父类的方法
*/
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy methodProxy) throws Throwable {
System.out.println("代理类" + obj.getClass());
System.out.println("方法名称" + method.getName());
if(args!=null && args.length>0) {//方法的参数值
for(int i=0; i<args.length; i++) {
System.out.println("方法参数" + args[i]);
}
Object returnvalue = null;//方法的返回值,无返回类型时,为null
returnvalue = methodProxy.invoke(this.targetObject, args);//调用目标对象的方法
System.out.println("方法的返回值" + returnvalue);
return returnvalue;
}
return null;
}
}
(3)spring的两种代理方式(默认是jdk动态代理)
* 若目标对象实现了若干接口,spring使用JDK的java.lang.reflect.Proxy类代理.
优点:因为有接口,所以使系统更加松耦合
缺点:为每一个目标类创建接口
* 若目标对象没有实现任何接口,spring使用CGLIB库生成目标对象的子类
优点:因为代理类与目标类是继承关系,所以不需要有接口的存在.
缺点:因为没有使用接口,所以系统的耦合性相对要差.
2.AOP编程
(1)概念
* Aspect(切面):比如说事务、权限等,与业务逻辑没有关系的部分.
* joinpoint(连接点):目标类的目标方法,由客户端在调用的时候决定
* Pointcut(切入点):指我们要对那些拦截的方法的定义,被纳入spring aop中的目标类的方法
* Advice(通知):指拦截到joinpoint之后要做的事情就是通知.
分为,前置通知、后置通知、异常通知、最终通知、环绕通知.
* Target(目标对象):代理的目标对象
* Weaving(织入)pid=11&gid=1:指把切面应用到目标对象来创建新的代理对象的过程.
切面在指定的连接点织入到目标对象.
(2)对应JDKProxy代理中的概念
SpringAop JDKProxy代理
目标对象 目标对象
切面 拦截器类
通知 拦截器类中的方法
切入点 被拦截到的目标类中方法的集合
连接点 在客户端调用的方法(目标类目标方法)
AOP代理 代理类
织入 代理类的代理方法生成的过程
(3)AOP实现的两种模式
* xml形式
- <!-- 在spring中配置文件中声明切面 -->
- <bean id="security" class="com.liu.aop.before.Security" />
- <!-- 在spring中配置文件中声明目标类 -->
- <bean id="userManager" class="com.liu.aop.before.UserManagerImpl"/>
- <!-- 定义切面、切入点、通知-->
- <aop:aspect id="securityid" ref="security">
- <aop:pointcut id="perform" expression="execution(* com.liu.aop.before.UserManagerImpl.save*(..))"/>
- <!--定义前置通知-->
- <aop:before method="checkSecurity" pointcut-ref="perform" />
- </aop:aspect>
- <!--定义切入点 ,让通知拦截到com.liu.aop.before.UserManagerImpl中以save开始的方法
- * 使用切入点指示符
- execution : 匹配方法执行的连接点,这是你将会用到的Spring的最主要的切入点指示符。
- * execution切入点指示符表达式如下:
- 例如:execution("public * com.liu.UserManagerImpl.*(..) throws Exception")
- execution( modifiers-pattern? 方法的修饰符模式:不是必须的
- ret-type-pattern: 返回类型模式:必须的
- declaring-type-pattern?: 路径模式,不是必须的.
- * 方法所在类的路径
- name-pattern:方法的名称 必须的
- *表示类中所有的方法
- "save*"表示类中以save开始的方法
- (param-pattern):参数模式,必须的
- * ():匹配了一个不接受任何参数的方法
- * (..):匹配了一个接受任意数量参数的方法.
- * 模式(*)匹配了一个接受一个任何类型的参数的方法
- * 模式(*,String)匹配了一个接受两个参数的方法,
- 第一个可以是任意类型,第二个必须是String类型
- throws-pattern? : 异常模式,抛出的异常 不是必须的
- 示例:
- * 任意公共方法的执行:execution(public * * (..))
- * 任何一个名字以set开始的方法的执行:execution(* set*(..))
- * AccountService接口定义的任意方法的执行:execution(* com.liu.service.AccountService.*(..))
- * 在service包中定义的任意方法的执行:execution(* com.liu.service..*(..))
- * 在service包或其子包中定义的任意方法的执行:execution(* com.liu.service..*.*(..))
- -->
<!-- 在spring中配置文件中声明切面 -->
<bean id="security" class="com.liu.aop.before.Security" />
<!-- 在spring中配置文件中声明目标类 -->
<bean id="userManager" class="com.liu.aop.before.UserManagerImpl"/>
<!-- 定义切面、切入点、通知-->
<aop:aspect id="securityid" ref="security">
<aop:pointcut id="perform" expression="execution(* com.liu.aop.before.UserManagerImpl.save*(..))"/>
<!--定义前置通知-->
<aop:before method="checkSecurity" pointcut-ref="perform" />
</aop:aspect>
<!--定义切入点 ,让通知拦截到com.liu.aop.before.UserManagerImpl中以save开始的方法
* 使用切入点指示符
execution : 匹配方法执行的连接点,这是你将会用到的Spring的最主要的切入点指示符。
* execution切入点指示符表达式如下:
例如:execution("public * com.liu.UserManagerImpl.*(..) throws Exception")
execution( modifiers-pattern? 方法的修饰符模式:不是必须的
ret-type-pattern: 返回类型模式:必须的
declaring-type-pattern?: 路径模式,不是必须的.
* 方法所在类的路径
name-pattern:方法的名称 必须的
*表示类中所有的方法
"save*"表示类中以save开始的方法
(param-pattern):参数模式,必须的
* ():匹配了一个不接受任何参数的方法
* (..):匹配了一个接受任意数量参数的方法.
* 模式(*)匹配了一个接受一个任何类型的参数的方法
* 模式(*,String)匹配了一个接受两个参数的方法,
第一个可以是任意类型,第二个必须是String类型
throws-pattern? : 异常模式,抛出的异常 不是必须的
示例:
* 任意公共方法的执行:execution(public * * (..))
* 任何一个名字以set开始的方法的执行:execution(* set*(..))
* AccountService接口定义的任意方法的执行:execution(* com.liu.service.AccountService.*(..))
* 在service包中定义的任意方法的执行:execution(* com.liu.service..*(..))
* 在service包或其子包中定义的任意方法的执行:execution(* com.liu.service..*.*(..))
-->
* 前置通知:
<aop:before method="checkSecurity" pointcut-ref="perform" />
* method="checkSecutiry":表示把切面(security)中checkSecurity方法定义为前置通知
* pointcut-ref="perform":把切入点应用到通知.
* 前置拦截的类必须实现MethodBeforeAdvice接口,实现其中的before方法
* 后置通知:
<aop:after-returning method="checkSecurity" pointcut-ref="perform" returning="val" />
* return="val" 通知里可以有返回参数,这个参数只能决定通知里能不能拿到方法的返回值,和客户端没关系.
* 在执行目标类的目标方法中遇到异常,则不执行后置通知.
* 后置拦截的类必须实现AfterReturningAdvice接口,实现其中的afterReturning方法.
* 在拦截器中的方法要和checkSecurity方法一样,有两个参数:
JoinPoint point : 可以获得目标方法和参数值
Object val :这里的名字要和return="val"中保持一致,指的是方法的返回值
* 最终通知:
<aop:after method="checkSecurity" pointcut-ref="perform" />
* 注意:最终通知不受异常影响,即不论目标方法执行的过程中是否抛出异常,最终通知都将执行.
* 环绕通知:
<aop:around method="checkSecurity" pointcut-ref="perform" />
* 前后拦截的类必须实现MethodInterceptor接口,实现其中的invoke方法.
* 异常通知:
<aop:after-throwing method="checkSecurity" pointcut-ref="perform" throwing="ex"/>
* 其中throwing指定了传递异常的参数名称
* 在异常通知中(拦截器)中,必须是checkSecurity方法
方法中有两个参数:
JoinPoint point:可以获得方法的名称、参数
Throwable ex : 利用ex.getMessage()可以获得异常信息
* 注解形式
为了在spring配置中使用@AspectJ切面,首先必须启用Spring对@AspectJ切面配置的支持,并确保自动代理
- <beans ...>
- <!-- 启用spring对@AspectJ的支持 -->
- <aop:aspectj-autoproxy/>
- <!-- 声明切面对象 -->
- <bean id="security" class="com.liu.service.Security"/>
- <!-- 创建接口实现类对象 -->
- <bean id="userManager" class="com.liu.service.UserManagerImpl"/>
- </beans>
- // 前置通知
- /* @Aspectj是按照类型匹配
- * @Pointcut用于声明切入点
- * 在@AspectJ注解风格的aop中,一个切入点签名通过一个普通的方法来定义
- * 1.作为切入点签名的方法必须返回void类型
- * 2.方法没有参数用private修饰
- * 3.方法体为空
- * 切入点表达式的写法
- * execution(..)表示匹配方法执行的连接点
- * 1."*"表示方法的返回类型任意
- * 2.com.liu.service..* 表示service包及其子包中所有的类
- * 3.save* 表示类中所有以save开头的方法
- * 4.(..)表示参数是任意数量
- * @Before 前置通知,在方法调用前执行
- * userManagerPointcut() 表示前面定义的切入点
- * args 限定匹配特定的连接点(使用spring AOP 的时候方法的执行),其中参数是指定类型的实例
- * username1,psw 参数表示指定类型的实例
- * 参数名称必须与通知的参数名称一致
- * 通知参数的类型必须与目标对象参数的类型一致,如不一致,则拦截不到
- */
- @Aspect
- public class Security {
- @Pointcut("execution(* com.liu.service..*.save*(..))")
- private void userManagerPointcut(){}
- @Before("userManagerPointcut() && args(username1,psw)")
- public void checkSecurity(String username1, String psw){
- System.out.println("安全检查"+username1+" "+psw);
- }
- }
- // 后置通知
- @Aspect
- public class Security {
- @Pointcut("execution(* com.liu.service..*.save*(..))")
- private void userManagerPointcut(){}
- @AfterReturning(pointcut="userManagerPointcut()",returning="value")
- public void checkSecurity(String value) {
- System.out.println("安全检查"+value);
- }
- }
- // 异常通知
- @Aspect
- public class Security {
- @Pointcut("execution(* com.liu.service..*.save*(..))")
- private void userManagerPointcut(){}
- @AfterThrowing(pointcut="userManagerPointcut()",throwing="ex")
- public void checkSecurity(Exception ex) {
- System.out.println("安全检查" + ex);
- }
- }
- // 最终通知
- @Aspect
- public class Security {
- @Pointcut("execution(* com.liu.service..*.save*(..))")
- private void userManagerPointcut(){}
- @After("userManagerPointcut()")
- public void checkSecurity(Exception ex) {
- System.out.println("安全检查");
- }
- }
- // 环绕通知
- @Aspect
- public class Security {
- @Pointcut("execution(* com.liu.service..*.save*(..))")
- private void userManagerPointcut(){}
- @Around("userManagerPointcut()")
- public Object checkSecurity(ProceedingJoinPoint point)throw Throwable {
- System.out.println("方法的名称" + point.getSignature().getName());
- System.out.println("测试参数对象是否为空" + point.getArgs().toString());
- if(point.getArgs().length > 0) {
- for(int i=0; i<point.getArgs().length; i++) {
- System.out.println("方法的参数值" + point.getArgs()[i]);
- }
- }
- Object returnvalue = null; //调用方法的返回值,方法无返回值时是null
- returnvalue=point.proceed(); //调用目标对象方法
- System.out.println("returnvalue" + returnvalue);
- System.out.prntln("进行安全检查");
- return returnvalue;
- }
- }
<beans ...>
<!-- 启用spring对@AspectJ的支持 -->
<aop:aspectj-autoproxy/>
<!-- 声明切面对象 -->
<bean id="security" class="com.liu.service.Security"/>
<!-- 创建接口实现类对象 -->
<bean id="userManager" class="com.liu.service.UserManagerImpl"/>
</beans>
// 前置通知
/* @Aspectj是按照类型匹配
* @Pointcut用于声明切入点
* 在@AspectJ注解风格的aop中,一个切入点签名通过一个普通的方法来定义
* 1.作为切入点签名的方法必须返回void类型
* 2.方法没有参数用private修饰
* 3.方法体为空
* 切入点表达式的写法
* execution(..)表示匹配方法执行的连接点
* 1."*"表示方法的返回类型任意
* 2.com.liu.service..* 表示service包及其子包中所有的类
* 3.save* 表示类中所有以save开头的方法
* 4.(..)表示参数是任意数量
* @Before 前置通知,在方法调用前执行
* userManagerPointcut() 表示前面定义的切入点
* args 限定匹配特定的连接点(使用spring AOP 的时候方法的执行),其中参数是指定类型的实例
* username1,psw 参数表示指定类型的实例
* 参数名称必须与通知的参数名称一致
* 通知参数的类型必须与目标对象参数的类型一致,如不一致,则拦截不到
*/
@Aspect
public class Security {
@Pointcut("execution(* com.liu.service..*.save*(..))")
private void userManagerPointcut(){}
@Before("userManagerPointcut() && args(username1,psw)")
public void checkSecurity(String username1, String psw){
System.out.println("安全检查"+username1+" "+psw);
}
}
// 后置通知
@Aspect
public class Security {
@Pointcut("execution(* com.liu.service..*.save*(..))")
private void userManagerPointcut(){}
@AfterReturning(pointcut="userManagerPointcut()",returning="value")
public void checkSecurity(String value) {
System.out.println("安全检查"+value);
}
}
// 异常通知
@Aspect
public class Security {
@Pointcut("execution(* com.liu.service..*.save*(..))")
private void userManagerPointcut(){}
@AfterThrowing(pointcut="userManagerPointcut()",throwing="ex")
public void checkSecurity(Exception ex) {
System.out.println("安全检查" + ex);
}
}
// 最终通知
@Aspect
public class Security {
@Pointcut("execution(* com.liu.service..*.save*(..))")
private void userManagerPointcut(){}
@After("userManagerPointcut()")
public void checkSecurity(Exception ex) {
System.out.println("安全检查");
}
}
// 环绕通知
@Aspect
public class Security {
@Pointcut("execution(* com.liu.service..*.save*(..))")
private void userManagerPointcut(){}
@Around("userManagerPointcut()")
public Object checkSecurity(ProceedingJoinPoint point)throw Throwable {
System.out.println("方法的名称" + point.getSignature().getName());
System.out.println("测试参数对象是否为空" + point.getArgs().toString());
if(point.getArgs().length > 0) {
for(int i=0; i<point.getArgs().length; i++) {
System.out.println("方法的参数值" + point.getArgs()[i]);
}
}
Object returnvalue = null; //调用方法的返回值,方法无返回值时是null
returnvalue=point.proceed(); //调用目标对象方法
System.out.println("returnvalue" + returnvalue);
System.out.prntln("进行安全检查");
return returnvalue;
}
}