Spring通知类型(入门使用方法)
需要导入的jar包
一.前置通知
作用:在目标方法执行之前执行的通知
1.定义一个含有业务方法的类
public class UserDao {
public void addUser(String name){
System.out.println("addUser,name:"+name);
}
2.前置通知类实现接口MethodBeforeAdvice中的方法
public class Log implements MethodBeforeAdvice {
Logger log=Logger.getLogger("test.Log");
@Override
public void before(Method arg0, Object[] arg1, Object arg2)
throws Throwable {
log.info(Level.INFO+",写日志");
}
3.配置beans.xml文件
<bean id="userDao" class="test.UserDao"/>
<bean id="log" class="test.Log"/>
<!-- 配置代理对象bean -->
<bean id="userDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="userDao"></property>
<property name="interceptorNames">
<list>
<value>log</value>
</list>
</property>
</bean>
4.编写测试类
public class Test {
public static void main(String[] args) {
//获取bean容器
ApplicationContext act=new ClassPathXmlApplicationContext("beans.xml");
//获取代理对象
UserDao userDaoProxy=(UserDao) act.getBean("userDaoProxy");
userDaoProxy.addUser("lisi");
}
}
二.后置通知
作用:在目标方法执行之后执行
1.定义一个接口
public interface UserDaoIfac {
public void addUser(String name);
}
2.创建实现接口的类
public class UserDao implements UserDaoIfac{
public void addUser(String name)
{
System.out.println("addUser,name:"+name);
}
}
3.创建后置通知类实现AfterReturningAdvice接口中的afterReturning方法(调用目标对象方法后拦截)
public class RecordInterceptor implements AfterReturningAdvice {
@Override
public void afterReturning(Object arg0, Method method, Object[] arg2,
Object arg3) throws Throwable {
System.out.println("ip 地址于"+new Date()+"访问方法"+method.getName());
}
4.配置beans.xml文件
<bean id="userDao" class="test.UserDao"/>
<bean id="RecordInterceptor" class="test.RecordInterceptor"/>
<!-- 配置代理对象bean -->
<bean id="userDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="userDao"></property>
<property name="interceptorNames">
<property name="proxyInterfaces" value="test.UserDaoIfac">
<list>
<value>recordInterceptor</value>
</list>
</property>
</bean>
5.编写测试类
public class Test {
public static void main(String[] args) {
//获取bean容器
ApplicationContext act=new ClassPathXmlApplicationContext("beans.xml");
//获取代理对象
UserDao userDaoProxy=(UserDao) act.getBean("userDaoProxy");
userDaoProxy.addUser("lisi");
}
}
三.环绕通知
作用:围绕着目标方法执行
1.定义一个接口
public interface UserDaoIfac {
public String addUser(String name);
}
2.创建实现接口的类
public class UserDao implements UserDaoIfac{
public String addUser(String name)
{
System.out.println("addUser,name:"+name);
}
return name;
}
3.创建环绕通知类实现MethodInterceptor接口中的invoke方法(调用目标对象方法会被关在这个方法中)
public class MyFilter implements MethodInterceptor{
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("进来了");
//调用目标对象方法
String result=(String)invocation.proceed();
System.out.println("走了");
return result;
}
}
4.配置beans.xml
<bean id="userDao" class="test.UserDao"/>
<bean id="myFilter" class="test.MyFilter"></bean>
<bean id="userDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interceptorNames">
<list>
<value>myFilter</value>
</list>
</property>
<!-- 如果面向接口编程,需要配置接口信息 -->
<property name="proxyInterfaces" value="test.UserDaoIfac"></property>
<property name="target" ref="userDao"></property>
</bean>
5.编写测试类
public class Test {
public static void main(String[] args) {
//获取bean容器
ApplicationContext act=new ClassPathXmlApplicationContext("beans.xml");
//获取代理对象
UserDao userDaoProxy=(UserDao) act.getBean("userDaoProxy");
userDaoProxy.addUser("lisi");
}
}
四.异常通知
作用:在目标方法抛出异常之后
1.定义一个接口
public interface UserDaoIfac {
public String addUser(String name);
}
2.创建实现接口的类
public class UserDao implements UserDaoIfac{
public String addUser(String name)
{
System.out.println("addUser,name:"+name);
int i = 2/0;//异常语句
}
return name;
}
3.创建异常通知类实现ThrowsAdvice接口中的afterThrowing方法(调用目标对象方法抛异常时执行)
public class MyExceptionAdvice implements ThrowsAdvice {
public void afterThrowing(Exception ex)
{
System.out.println("异常信息 :"+ex.getMessage());
}
}
4.配置beans.xml
<bean id="userDao" class="test.UserDao"/>
<bean id="myExceptionAdvice" class="test.MyExceptionAdvice"></bean>
<bean id="userDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interceptorNames">
<list>
<value>myExceptionAdvice</value>
</list>
</property>
<!-- 如果面向接口编程,需要配置接口信息 -->
<property name="proxyInterfaces" value="test.UserDaoIfac"></property>
<property name="target" ref="userDao"></property>
</bean>
5.编写测试类
public class Test {
public static void main(String[] args) {
//获取bean容器
ApplicationContext act=new ClassPathXmlApplicationContext("beans.xml");
//获取代理对象
UserDao userDaoProxy=(UserDao) act.getBean("userDaoProxy");
userDaoProxy.addUser("lisi");
}
}
缺点:如果要对多个类进行拓展,那么就要手动配置多个bean代理,工作量大且不好维护。
SpringAOP之xmlConfig高级实现
1.定义一个含有业务方法的类
public class UserDao {
public void addUser(String name)
{
System.out.println("addUser,name:"+name);
}
public void deleteUser(String name)
{
System.out.println("deleteUser,name:"+name);
}
}
2.定义功能拓展类
前置通知记录日志
public class Log {
Logger log=Logger.getLogger("test.Log");
public void before(){
log.info(Level.INFO+",写日志");
}
后置通知记录ip
public class IPRecord {
public void ipRecord()
{
System.out.println("ipRecord");
}
}
3.配置beans.xml 配置文件中多了3个AOP的属性文件
xmlns:aop=“http://www.springframework.org/schema/aop”
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
<?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:p="http://www.springframework.org/schema/p"
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
">
<bean id="userDao" class="test.UserDao"/>
<bean id="log" class="test.Log"/>
<bean id="iPRecord" class="test.IPRecord"/>
<!-- 使用aop配置语法,配置切面,切入点和目标对象之间的关联关系 -->
<aop:config>
<!-- 可以配置多个,比如拦截dao的逻辑 比如拦截service的逻辑 比如拦截controller的逻辑都可以配置在这里 -->
<aop:aspect id="myaspect" ref="log">
<aop:pointcut expression="execution(* test.UserDao.add*(..))" id="addMethod"/>
<aop:before method="before" pointcut-ref="addMethod"/>
</aop:aspect>
<aop:aspect id="mydeleteAspect" ref="iPRecord">
<aop:pointcut expression="execution(* test..*.delete*(..))" id="deleteMethod"/>
<aop:after method="ipRecord" pointcut-ref="deleteMethod"/>
</aop:aspect>
</aop:config>
</beans>
execution(* test.UserDao.add*(…)) 解释
{
*:不管方法有没有返回值
add*:test.UserDao下的所有add方法
(…):不管方法需不需要参数
}执行
4.编写测试类
public static void main(String[] args) {
ApplicationContext act=new ClassPathXmlApplicationContext("beans.xml");
UserDao userDao=(UserDao) act.getBean("userDao");
userDao.addUser("张三");
userDao.deleteUser("lisi");
}
5.测试结果
SpringAOP之annotcation高级实现
1.定义一个含有业务方法的类
public class UserDao {
public void addUser(String name)
{
System.out.println("addUser,name:"+name);
}
public void deleteUser(String name)
{
System.out.println("deleteUser,name:"+name);
}
}
2.配置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:p="http://www.springframework.org/schema/p"
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
">
<bean id="userDao" class="test.UserDao"/>
<bean id="log" class="test.Log"/>
<bean id="iPRecord" class="test.IPRecord"/>
<!-- 使用注解,配置则写在拦截器上面,xml文件中要开启注解支持 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
3.使用注解编写功能拓展类
@Aspect:使其成为切面类
@Pointcut:切入点
@Before:前置通知
@After:后置通知
@Aspect
public class Log {
Logger log=Logger.getLogger("test.Log");
@Pointcut("execution(* test.UserDao.add*(..))")
private void addMethod(){}
//怎么配置切谁 pointcut 通过一个傀儡方法配置
@Before(value="addMethod()")//前置通知
public void abc(){
log.info(Level.INFO+",写日志");
}
}
@Aspect
public class IPRecord {
Logger log=Logger.getLogger("test.IPRecord");
@Pointcut("execution(* test.UserDao.delete*(..))")
private void deleteMethod(){}
@After(value="deleteMethod()")
public void ipRecord()
{
log.info(Level.INFO+",ip地址");
}
}
4.测试
public static void main(String[] args) {
ApplicationContext act=new ClassPathXmlApplicationContext("beans.xml");
UserDao userDao=(UserDao) act.getBean("userDao");
/**
* 终于可以直接调用目标对象然后发现功能被扩展了
*/
userDao.addUser("张三");
userDao.deleteUser("lisi");
}
5.执行结果
常用表达式tips:
第一种:表示在UserMangeImpl类下的所有方法,这种方式在之前的案例使用的。
@Pointcut("execution(* com.spring.two.UserMangeImpl.*(..))")
第二种:表示任意公共的方法,其他修饰符也同样的道理。
@Pointcut("execution(public * *(..))")
第三种:任何一个以set开始的方法,不仅仅是set,save、update也都行。
@Pointcut("execution(* set*(..))")
第四种:在指定包下的所有方法
@Pointcut("execution(* com.spring.*.*(..))")