Day67 Spring AOP(面向切面编程) 和代理设计模式

Spring AOP 概念

Spring AOP学习:
    问题:
        Spring IOC实现了对象之间依赖关系的解耦。如果开发过程中,需要更改对象,只需要
        在配置文件中更改对象的配置路径即可完成对象的更换。但是,在保留原有对象的基础上
        对原有功能代码进行功能扩展,是Spring IOC所不能实现的。
    解决:
        使用Spring AOP
        特点:
            在不改变原有对象的功能代码的基础上完成功能扩展。
    概念:
        面向切面的编程(扩展)。
    术语:
        前置通知:在原有功能执行之前扩充的代码。
        后置通知:在原有功能执行之后扩充的代码。
        切点:原有功能方法
        织入:前置通知+切点+后置通知形成切面的过程
        切面:前置通知+切点+后置通知形成的横向执行流程。
    使用:
        Schema-based方式
        Aspectj方式
        基于Aspectj的注解方式
    流程:
        导入jar包
        配置配置文件
        完成扩展


Schema-based方式

Schema-Based方式:
    第一步:
        导入jar包(Spring IOC包+AOP相关包)
    第二步:
        在src下创建applicationcontext.xml配置文件
            加载Schema:
                <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"
    xmlns:myns="http://www.mycompany.com/schema/myns"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.mycompany.com/schema/myns http://www.mycompany.com/schema/myns/myns.xsd
         http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
                    ">
            配置相关bean
            配置通知bean
            配置切面
    第三步:
        创建通知类
            前置通知:
                创建一个实现了MethodBeforeAdvice接口的java类
                实现接口方法before
                    参数:
                        Method arg0:切点方法对象
                        Object[] arg1:切点接收的实参数组
                        Object arg2:切点所在的对象
                在配置文件中配置通知bean
                在切面配置中配置关联
            后置通知
                创建一个实现了AfterReturningAdvice接口的java类
                实现接口方法afterReturning
                    参数:
                        Object arg0:切点的返回值
                        Method arg0:切点方法对象
                        Object[] arg1:切点接收的实参数组
                        Object arg2:切点所在的对象
                在配置文件中配置通知bean
                在切面配置中配置关联
            环绕通知
                创建一个实现了MethodInterceptor接口的java类
                实现接口方法invoke
                        参数:
                        MethodInvocation arg0:放行切点
                在配置文件中配置通知bean
                在切面配置中配置关联
                注意:
                    在实现方法中需要对切点方法进行放行:  Object obj=arg0.proceed();//放行,执行切点方法。
            异常通知
                创建一个实现了ThrowsAdvice接口的java类
                实现接口方法afterThrowing
                    public void afterThrowing(Exception ex) throws Throwable {
                        System.out.println("我是异常通知");
                     }
                    Exception ex:接收的是切点的异常对象。
                在配置文件中配置通知bean
                在切面配置中配置关联
                注意:
                    切点中的内部如果使用异常处理机制,则无法触发异常通通知。
        通配符的作用:
            1   <aop:pointcut expression="execution(* com.bjsxt.pojo.Car2.demo(..))" id="my"/><!--配置切点 -->
                其中切点方式使用..表示参数个数个类型为任意,只要是方法名为demo的都会添加通知。
            2   <aop:pointcut expression="execution(* com.bjsxt.pojo.Car2.*(..))" id="my"/><!--配置切点 -->
                  *是通配符,表示任意的方法名,类名,包名等。

    第四步:        
        由Spring容器对象获取切点所在bean对象
        调用切点方法完成功能操作。
-------------------------------------------------------------------------------------------------------
<?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"
    xmlns:myns="http://www.mycompany.com/schema/myns"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.mycompany.com/schema/myns http://www.mycompany.com/schema/myns/myns.xsd
         http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        ">
    <!-- 配置bean 没有使用Spring AOP -->
        <bean id="car" class="com.bjsxt.pojo.Car"></bean>
    <!--配置bean  使用Spring AOP-->
        <!--Schema-Based方式  -->
            <!--配置切点bean  -->
                <bean id="car2" class="com.bjsxt.pojo.Car2"></bean>
            <!--配置前置通知bean  -->
                <bean id="before" class="com.bjsxt.advice.MyBefore"></bean>
            <!--配置后置通知bean  -->
                <bean id="after" class="com.bjsxt.advice.MyAfter"></bean>
            <!--配置环绕通知bean  -->
                <bean id="round" class="com.bjsxt.advice.MyRound"></bean>
            <!--配置异常通知bean  -->
                <bean id="throw" class="com.bjsxt.advice.MyThrow"></bean>
            <!--配置切面  -->
            <aop:config>
                <aop:pointcut expression="execution(* com.*.pojo.Car2.*(..))" id="my"/><!--配置切点 -->
                <aop:advisor advice-ref="before" pointcut-ref="my"/><!--配置前置通知 -->
                <aop:advisor advice-ref="after" pointcut-ref="my"/><!--配置后置通知  -->
                <aop:advisor advice-ref="round" pointcut-ref="my"/><!-- 配置环绕通知 -->
                <aop:advisor advice-ref="throw" pointcut-ref="my"/><!-- 配置异常通知 -->
            </aop:config>

</beans>

基于AspectJ方式

AspectJ方式:
    第一步:
        导入jar包(Spring IOC+AOP包)
    第二步:
        在Src下创建applicationcontext.xml
            加载Schema(IOC和AOP相关)
            配置相关bean
    第三步:
        创建通知类
            创建一个普通java类,创建四个方法。
            前置通知方法
            后置通知方法
            环绕通知方法
                public Object round(ProceedingJoinPoint p) throws Throwable{
        System.out.println("AspectJ方式--环绕--前置");
        Object obj=p.proceed();
        System.out.println("AspectJ方式--环绕--后置");
        return obj;
                }
            异常通知方法
        在applicationcontext.xml中配置通知bean
            <bean id="advice" class="com.bjsxt.adviceAs.Myadvice"></bean>
        在applicationcontext.xml中配置切面
            <aop:config>
                    <aop:aspect ref="advice">
                        <aop:pointcut expression="execution(* com.bjsxt.pojo.Car3.demo())" id="my1"/><!--配置切点  -->
                        <aop:before method="before" pointcut-ref="my1"/><!--前置通知  -->
                        <aop:after-returning method="after" pointcut-ref="my1"/><!--后置通知  -->
                        <aop:around method="round" pointcut-ref="my1"/><!-- 环绕通知 -->
                        <aop:after-throwing method="myThrow" pointcut-ref="my1" throwing="e"/><!--异常通知  -->
                    </aop:aspect>
            </aop:config>

第四步:
        创建Spring容器对象
        获取切点bean对象
        调用切点方法
总结:
    AspectJ配置方式的通知方法中要获取切点的参数,配置特别麻烦,切点不能通配。
    如果不需要切点的参数则使用AspectJ方式
    如果需要参数使用Schema-based方式
-------------------------------------------------------------------------

使用注解(基于AspectJ)

@Component  默认使用无参构造器
Spring默认使用JDK代理模式

基于Aspectj的注解配置AOP:
    1 导入jar包
    2 创建Spring配置文件并完成基础配置
        加载Schema
        配置数据源
        配置工厂
        配置扫描
    3 Spring使用注解配置
            在spring配置文件中增加context的先关Schema
                <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"
    xmlns:context="http://www.springframework.org/schema/context"
    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
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        ">
            在Spring配置文件中配置注解扫描:
                 <context:component-scan base-package="com.bjsxt.advice,com.bjsxt.pojo"></context:component-scan>
            注意:必须在Spring配置文件中声明使用了注解的类的包路径
    4 使用注解替换XML的配置
        替换bean配置(通用)
            @Component
                 在类名上直接使用此注解,表示bean创建,相当于在Spring中配置了该类的bean标签。
                类名首字母小写即为bean 的ID
        替换切面配置
            替换切点声明
                在切点方法上直接使用@Pointcut注解声明切点,示例如下:
                @Pointcut("execution(* com.bjsxt.pojo.Demo.demo())")
    public void demo(){
        System.out.println("Demo.demo()");
    }
            替换通知方法的配置
                在通知类的类名上还要使用@Aspect进行声明该类为通知类。
                在类的通知方法上使用注解
                    前置通知:@Before("切点的全限定路径")  示例:
                            @Before("com.bjsxt.pojo.Demo.demo()")
    public void myBefore(){
        System.out.println("注解----前置通知");
    }
                    后置通知
                        @After("com.bjsxt.pojo.Demo.demo()")
    public void after(){

        System.out.println("注解---后置通知");
    }
                    环绕通知
         @Around("com.bjsxt.pojo.Demo.demo()")
    public Object round(ProceedingJoinPoint p) throws Throwable{
        System.out.println("注解--环绕--前置");
        Object obj=p.proceed();
        System.out.println("注解--环绕--后置");
        return obj;
    }
                    异常通知    
@AfterThrowing("com.bjsxt.pojo.Demo.demo()")
    public void myThrow(){

        System.out.println("注解---异常");
    }

注意:
    一定要将动态代理模式设置为cglib代理模式
         <!--配置动态代理模式  -->
         <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
--------------------------------------------------------------------------------------------------------------------------------------------
Spring配置文件中的配置
        <?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"
    xmlns:context="http://www.springframework.org/schema/context"
    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
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        ">
        <!--配置注解扫描  -->
        <context:component-scan base-package="com.bjsxt.advice,com.bjsxt.pojo"></context:component-scan>
        <!--配置动态代理模式  -->
        <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
</beans>
切点Bean的配置:
        package com.bjsxt.pojo;

import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Component
public class Demo {
    @Pointcut("execution(* com.bjsxt.pojo.Demo.demo())")
    public void demo(){
        System.out.println("Demo.demo()");
    }
}
通知Bean的配置和切面的配置
package com.bjsxt.advice;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class MyAdvice {
    @Before("com.bjsxt.pojo.Demo.demo()")
    public void myBefore(){
        System.out.println("注解----前置通知");
    }

    @After("com.bjsxt.pojo.Demo.demo()")
    public void after(){

        System.out.println("注解---后置通知");
    }
    @Around("com.bjsxt.pojo.Demo.demo()")
    public Object round(ProceedingJoinPoint p) throws Throwable{
        System.out.println("注解--环绕--前置");
        Object obj=p.proceed();
        System.out.println("注解--环绕--后置");
        return obj;
    }
    @AfterThrowing("com.bjsxt.pojo.Demo.demo()")
    public void myThrow(){

        System.out.println("注解---异常");
    }
}

小案例

需求:
这里写图片描述
导入包:
aopalliance.jar
asm-3.3.1.jar
aspectjweaver.jar
cglib-2.2.2.jar
commons-logging-1.1.1.jar
commons-logging-1.1.3.jar
javassist-3.17.1-GA.jar
log4j-1.2.17.jar
log4j-api-2.0-rc1.jar
log4j-core-2.0-rc1.jar
mybatis-3.2.7.jar
mybatis-spring-1.2.3.jar
mysql-connector-java-5.1.30.jar
slf4j-api-1.7.5.jar
slf4j-log4j12-1.7.5.jar
spring-aop-4.1.6.RELEASE.jar
spring-aspects-4.1.6.RELEASE.jar
spring-beans-4.1.6.RELEASE.jar
spring-context-4.1.6.RELEASE.jar
spring-core-4.1.6.RELEASE.jar
spring-expression-4.1.6.RELEASE.jar
spring-jdbc-4.1.6.RELEASE.jar
spring-tx-4.1.6.RELEASE.jar
spring-web-4.1.6.RELEASE.jar

数据库根据实体类去创建
相关代码:
Src:
com.bjsxt.advice:
MyAfter.java:

package com.bjsxt.advice;

import java.lang.reflect.Method;
import java.util.Date;

import org.apache.log4j.Logger;
import org.springframework.aop.AfterReturningAdvice;

public class MyAfter implements AfterReturningAdvice{

    @Override
    public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable {
        //创建日志对象
                Logger logger=Logger.getLogger(MyBefore.class);
        //校验
                if(arg0!=null){
                    logger.debug(arg2[0]+"在"+new Date().toLocaleString()+"登陆成功");
                }else{
                    logger.debug("查无此人:"+arg2[0]+":登陆失败");
                }

    }

}

MyBefore.java:

package com.bjsxt.advice;

import java.lang.reflect.Method;
import java.util.Date;

import org.apache.log4j.Logger;
import org.springframework.aop.MethodBeforeAdvice;

public class MyBefore implements MethodBeforeAdvice{

    @Override
    public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
        //创建日志对象
        Logger logger=Logger.getLogger(MyBefore.class);
        //输出日志
        logger.debug(arg1[0]+"在"+new Date().toLocaleString()+"点进行了登陆请求");

    }

}

com.bjsxt.mapper:
UserMapper.java:

package com.bjsxt.mapper;

import com.bjsxt.pojo.User;

public interface UserMapper {

    //查询用户信息---登录功能
    User selUser(String uname,String pwd);

}

UserMapper.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bjsxt.mapper.UserMapper">
    <!--根据用户名和密码查询用户信息  -->
    <select id="selUser" resultType="com.bjsxt.pojo.User" > 
        select * from t_user where uname=#{0} and pwd=#{1}
    </select>   
</mapper>

com.bjsxt.pojo:
User.java:

package com.bjsxt.pojo;

public class User {
    private int uid;
    private String uname;
    private String pwd;
    private String uphone;
    public int getUid() {
        return uid;
    }
    public void setUid(int uid) {
        this.uid = uid;
    }
    public String getUname() {
        return uname;
    }
    public void setUname(String uname) {
        this.uname = uname;
    }
    public String getPwd() {
        return pwd;
    }
    public void setPwd(String pwd) {
        this.pwd = pwd;
    }
    public String getUphone() {
        return uphone;
    }
    public void setUphone(String uphone) {
        this.uphone = uphone;
    }
    @Override
    public String toString() {
        return "User [uid=" + uid + ", uname=" + uname + ", pwd=" + pwd + ", uphone=" + uphone + "]";
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((pwd == null) ? 0 : pwd.hashCode());
        result = prime * result + uid;
        result = prime * result + ((uname == null) ? 0 : uname.hashCode());
        result = prime * result + ((uphone == null) ? 0 : uphone.hashCode());
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        User other = (User) obj;
        if (pwd == null) {
            if (other.pwd != null)
                return false;
        } else if (!pwd.equals(other.pwd))
            return false;
        if (uid != other.uid)
            return false;
        if (uname == null) {
            if (other.uname != null)
                return false;
        } else if (!uname.equals(other.uname))
            return false;
        if (uphone == null) {
            if (other.uphone != null)
                return false;
        } else if (!uphone.equals(other.uphone))
            return false;
        return true;
    }
    public User() {
        super();
        // TODO Auto-generated constructor stub
    }
    public User(int uid, String uname, String pwd, String uphone) {
        super();
        this.uid = uid;
        this.uname = uname;
        this.pwd = pwd;
        this.uphone = uphone;
    }



}

com.bjsxt.service:
UserService.java:

package com.bjsxt.service;

import com.bjsxt.pojo.User;

public interface UserService {

    /**
     * 查询用户信息
     * @param uname 用户名
     * @param pwd   密码
     * @return      返回存储了用户信息的User对象
     */
    User selUserService(String uname,String pwd);
}

com.bjsxt.serviceImpl:
UserServiceImpl.java:

package com.bjsxt.serviceImpl;

import com.bjsxt.mapper.UserMapper;
import com.bjsxt.pojo.User;
import com.bjsxt.service.UserService;

public class UserServiceImpl implements UserService {
    // 声明mapper接口属性
    private UserMapper um;

    public UserMapper getUm() {
        return um;
    }

    public void setUm(UserMapper um) {
        this.um = um;
    }
    //查询用户信息---登录功能
    @Override
    public User selUserService(String uname, String pwd) {
        return um.selUser(uname, pwd);
    }

}

com.bjsxt.servlet:
UserServlet.java:

package com.bjsxt.servlet;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import com.bjsxt.pojo.User;
import com.bjsxt.service.UserService;

/**
 * Servlet implementation class UserServlet
 */
@WebServlet("/us")
public class UserServlet extends HttpServlet {
    //声明业务层对象
        private UserService us;
    //初始化
        @Override
        public void init() throws ServletException {
            //获取Spring容器对象
            ApplicationContext ac=WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
            //给业务层对象赋值
            us=(UserService) ac.getBean("us");
        }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置请求编码格式
        req.setCharacterEncoding("utf-8");
        //设置响应编码格式
        resp.setCharacterEncoding("utf-8");
        resp.setContentType("text/html;charset=utf-8");
        //获取请求信息
        String uname=req.getParameter("uname");
        String pwd=req.getParameter("pwd");
        //处理请求信息
            //获取业务层对象
            User u=us.selUserService(uname, pwd);
        //响应处理结果
            if(u!=null){
                resp.sendRedirect("main.jsp");
            }else{
                req.getRequestDispatcher("login.jsp").forward(req, resp);
            }
    }

}

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 id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
                <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis"></property>
                <property name="username" value="root"></property>
                <property name="password" value="1234"></property>
            </bean>
        <!--  配置工厂-->
            <bean id="factory" class="org.mybatis.spring.SqlSessionFactoryBean">
                <property name="dataSource" ref="dataSource"></property>
            </bean>
        <!-- 配置mapper扫描 -->
            <bean id="mapper" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
                <property name="basePackage" value="com.bjsxt.mapper"></property>
                <property name="sqlSessionFactory" ref="factory"></property>
            </bean>
        <!--配置其他bean  -->
            <!--配置业务bean  -->
                <bean id="us" class="com.bjsxt.serviceImpl.UserServiceImpl">
                    <property name="um" ref="userMapper"></property>
                </bean>
            <!--配置通知bean  -->
                <bean id="before" class="com.bjsxt.advice.MyBefore"></bean>
                <bean id="after" class="com.bjsxt.advice.MyAfter"></bean>
            <!--配置切面  -->
                <aop:config>
                    <aop:pointcut expression="execution(* com.bjsxt.serviceImpl.UserServiceImpl.selUserService(..))" id="my"/>
                    <aop:advisor advice-ref="before" pointcut-ref="my"/>
                    <aop:advisor advice-ref="after" pointcut-ref="my"/>
                </aop:config>

</beans>

log4j.properties:


log4j.rootCategory=info



log4j.logger.com.bjsxt.mapper=debug, CONSOLE
log4j.logger.com.bjsxt.advice=debug, CONSOLE

log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=- %c-%d-%m%n


log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=D:\axis.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=- %c-%d-%m%n

WebContent:
login.jsp:

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>
    <form action="us" method="get">
        用户名:<input type="text"  name="uname" value=""/><br />
        密码:<input type="password"  name="pwd"/><br />
        <input type="submit" value="提交" />
    </form>
</body>
</html>

WEB-INF:
web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
     <!--配置Spring配置文件路径  -->
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:applicationcontext.xml</param-value>
        </context-param>
     <!--配置监听器  -->
        <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>
</web-app>

源码地址:
链接:https://pan.baidu.com/s/1n31EHGehJi8TqvImoJM2bw 密码:gl6b

代理模式

其他链接
https://blog.csdn.net/cckevincyh/article/details/54962920
https://blog.csdn.net/u013126379/article/details/52121096

代理设计模式:
    静态代理设计模式:
            真实类:要进行功能扩展的类
            代理类:进行功能扩展的类
            接口:真实类和代理类都要实现
                代理流程:
                代理类和真实类必须实现同一个接口
                在代理类中调用真实类的方法,并完成功能扩展
                修改调用方法为调用代理类
            缺陷:
                代理类又程序员自己编写。
            优点:
                扩展真实类的功能
                让真实类的方法功能更加明确。
                保护真实对象
    动态代理设计模式:    
            特点:
                动态生成代理对象。
            JDK动态代理:    基于 接口
                第一步:创建一个实现InvocationHandler接口的java类
                      并实现invoke方法
                    参数:
                        Object arg0:表示动态产生的代理对象
                        Method arg1:表示真实方法的Method对象
                        Object[] arg2:表示接收的实参
                    注意:
                        写的是功能扩展代码。
                第二步:
                    使用Proxy对象动态创建代理对象:
                        Proxy.newProxyInstance(TestBoss.class.getClassLoader(),new Class[]{Gongneng.class},new TestJdk());
                        使用返回值调用接口方法完成业务处理即可
                    注意:
                        该方法返回的是代理对象。

                特点:
                    动态的产生代理对象
                    基于接口的,代理对象和真实对象需要实现相同的接口
                    不用导入jar包
                    基于反射,效率低下
        cglib动态代理   :基于继承
第一步:
        创建一个实现了MethodInterceptor接口的java类
        实现接口方法:
        @Override
    public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable {
        System.out.println("你预约了吗?");
        arg1.invoke(new Boss(), arg2);
        System.out.println("记录吃饭记录");
        return null;
    }       
    Object arg0, 代理对象
    Method arg1,   真实方法对象
    Object[] arg2, 参数
                    MethodProxy arg3    代理方法对象

            第二步:动态获取代理对象
                Enhancer en=new Enhancer();
            en.setSuperclass(Boss.class);//声明要继承的实现类
            en.setCallback(new  TestCglib());
            Boss b2=(Boss)en.create();
            b2.eat();
            第三步:使用代理对象完成功能处理
            特点:
                基于继承的,效率较高
                需要导入jar包






小结

Spring Aop概念学习
Schema-based方式
基于AspectJ方式
使用注解(基于AspectJ)
小案例
代理模式

猜你喜欢

转载自blog.csdn.net/qq_21953671/article/details/79779635