Spring 框架总结

Spring 框架总结

一、Spring框架简介

1、Spring 框架的核心是 AOP 与 IOC (DI) 框架
2、IOC -->控制反转

​ Spring 将对象封装为 Bean,通过工厂模式实现对象注入,并给对象赋值

2、AOP -->切片

​ Spring 通过代理模式,可将对象进行拦截切片,从而赋予对象新的能力。

二、Spring管理MyBatis

1、依赖
 <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>4.3.6.RELEASE</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>4.3.6.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.6.8</version>
    </dependency>
    <dependency>
      <groupId>cglib</groupId>
      <artifactId>cglib</artifactId>
      <version>3.2.4</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>4.3.6.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>4.3.6.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-beans</artifactId>
      <version>4.3.6.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.3.6.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>1.3.2</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>4.3.6.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.4</version>
    </dependency>
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.10</version>
    </dependency>
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.42</version>
    </dependency>

​ 2、Spring-Mybatis.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:tx="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">
<!--jdbc:加载配置参数-->
    <context:property-placeholder location="classpath:res/db.properties"/>
<!--druid:创建数据源-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
<!--mybatis:创建sqlSessionFactory对象-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="typeAliasesPackage" value="com.qf.pojo"/>
        <property name="mapperLocations" value="mapping/*.xml"/>
    </bean>
<!--spring:扫描mapper-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.qf.dao"/>
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
    </bean>
<!--事务:创建JDBC事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
<!--事务管理:标签开发-->
    <tx:aspectj-autoproxy proxy-target-class="true"/>
<!--扫描所有的service-->
    <context:component-scan base-package="com.qf.service"/>
</beans>
3、db.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/traffic_manager?characterEncoding=utf8
jdbc.username=root
jdbc.password=95107530

三、常用标签

​1、@Component -->定义在 Service 实现类上,用于标记为Service,供Spring扫描
2、@AutoWired -->定义在属性上,用于标记属性,供Spring注入Service对象
3、@Transactional(isolation=Isolation.READ_COMMITTED , propagation=Propagation.REQUIRED , readOnly=false , rollbackFor=Exception.class , timeout=-1) —> 开启事务,定义在方法上则该方法带事务,定义在类上则整个类带事务。
@Component
public class ServiceImpl{
    
    @AutoWired
    private Serive service;
    
    @Transactional(isolation=Isolation.READ_COMMITTED , propagation=Propagation.REQUIRED , readOnly=false , rollbackFor=Exception.class , timeout=-1) 
    public void doService(){
        service.CURD();
    }
}

四、IoC(控制反转)

1、正转

​ 调用者创建对象,controller中有service的实现,service中有dao的实现,你中有我我中有你,容易造成代码的耦合,入侵性强,对代码的健壮性与可扩展性都有影响。

2、反转

​ 通过Spring动态生成一个对象,不需要调用者再去创建对象,入侵性弱,降低模块与模块间的耦合。

3、依赖
<dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.3.6.RELEASE</version>
    </dependency>
  </dependencies>
4、bean对象

​ (1)在Spring中将java对象处理为bean对象,只需要在xml文件中写入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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="stu" class="com.qf.pojo.Student"></bean>
</beans>

​ (2)IoC的作用范围(Scope)

​ a、jar包(2)——》singleton(单例模式)、prototype(多例模式)

​ b、war包(5)——》request(同一个request中为单例模式)、session(同一个会话中为单例模式

​ global_Session(同一个web应用中为单例模式)

注:(1)scope默认值为singleton,且为饿汉模式

(2)lazy_init=“true”为懒加载,即不到万不得已不会加载

(3)用标签创建对象,必须有无参构造

5、property

​ (1)在标签内写标签,通过name,value给对象赋值。

​ (2)8种基本数据类型以及String类型可直接通过value赋值。

​ (3)引用类型通过name,ref赋值;ref的值为其他bean的id。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       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">
    
     <bean id="addr" class="com.qf.pojo.Address">
        <property name="area" value="小南"/>
        <property name="city" value="小北"/>
        <property name="province" value="小兰"/>
    </bean>
       
    <bean id="stu" class="com.qf.pojo.Student">
        <property name="id" value="1"/>
        <property name="name" value="小张"/>
        <property name="money" value="1.25"/>
        <property name="address" ref="addr"/>
    </bean>
</beans>

注:通过标签每个属性必须有setter方法

6、constructor-arg

​ (1)通过标签创建有参构造器

​ (2)通过name,value对构造器中的参数赋值

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       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">

    <bean name="birth" class="java.util.Date">
        <constructor-arg name="year" value="19"/>
        <constructor-arg name="month" value="2"/>
        <constructor-arg name="date" value="15"/>
    </bean>

    <bean id="stu" class="com.qf.pojo.Student">
        <constructor-arg name="id" value="1"/>
        <constructor-arg name="name" value="小张"/>
        <constructor-arg name="money" value="1.25"/>
        <constructor-arg type="java.util.Date" ref="birth"/>
    </bean>
</beans>

​ (3)通过index,value对构造器中的参数赋值

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       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">

    <bean name="birth" class="java.util.Date">
        <constructor-arg index="0" value="19"/>
        <constructor-arg index="1" value="2"/>
        <constructor-arg index="2" value="15"/>
    </bean>

    <bean id="stu" class="com.qf.pojo.Student">
        <constructor-arg index="0" value="1"/>
        <constructor-arg index="1" value="小张"/>
        <constructor-arg index="2" value="1.25"/>
        <constructor-arg index="3" ref="addr"/>
        <constructor-arg index="4" ref="birth"/>
    </bean>
</beans>

​ (4)通过type,value赋值

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       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">

    <bean id="addr" class="com.qf.pojo.Address">
        <property name="area" value="小南"/>
        <property name="city" value="小寒"/>
        <property name="province" value="小溪"/>
    </bean>

    <bean name="birth" class="java.util.Date">
        <constructor-arg index="0" value="19"/>
        <constructor-arg index="1" value="2"/>
        <constructor-arg index="2" value="15"/>
    </bean>

    <bean id="stu" class="com.qf.pojo.Student">
        <constructor-arg type="java.lang.Integer" value="1"/>
        <constructor-arg type="java.lang.String" value="小张"/>
        <constructor-arg type="java.lang.Double" value="1.25"/>
        <constructor-arg type="com.qf.pojo.Address" ref="addr"/>
        <constructor-arg type="java.util.Date" ref="birth"/>
    </bean>
</beans>

注:Spring会根据参数的顺序匹配type,若两个参数的类型相同,则前一个type会匹配参数列表中第一个类型为其对应类型的参数。

​ (5)通过value或ref直接赋值

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       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">

    <bean id="addr" class="com.qf.pojo.Address">
        <property name="area" value="小明"/>
        <property name="city" value="校长/>
        <property name="province" value="小美"/>
    </bean>

    <bean name="birth" class="java.util.Date">
        <constructor-arg index="0" value="19"/>
        <constructor-arg index="1" value="2"/>
        <constructor-arg index="2" value="15"/>
    </bean>

    <bean id="stu" class="com.qf.pojo.Student">
        <constructor-arg value="1"/>
        <constructor-arg value="小张"/>
        <constructor-arg value="1.25"/>
        <constructor-arg ref="addr"/>
        <constructor-arg ref="birth"/>
    </bean>
</beans>

注:通过这种方式赋值必须要注意参数列表的顺序,constructor-arg的顺序必须要与参数列表顺序一致

7、p命名空间

​ (1)在声明标签的时候可通过p直接对其属性赋值,可不用通过标签赋值

​ (2)p命名空间

xmlns:p="http://www.springframework.org/schema/p"

注:p为局部变量,可以随意起名,但约定俗成为p

​ (3)通过 p:属性名=“属性值”对8种基本数据类型以及String类型赋值

​ (4)通过 p:属性名-ref=“id” 对引用类型赋值

<?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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="addr" class="com.qf.pojo.Address">
        <property name="area" value="小寒"/>
        <property name="city" value="小韩"/>
        <property name="province" value="小溪"/>
    </bean>

    <bean name="birth" class="java.util.Date">
        <constructor-arg index="0" value="19"/>
        <constructor-arg index="1" value="2"/>
        <constructor-arg index="2" value="15"/>
    </bean>

    <bean id="stu" class="com.qf.pojo.Student" p:id="1" p:address-ref="addr" p:birthday-ref="birth" p:money="1.25" p:name="小吴"></bean>
</beans>
8、Spring注入数组与集合

(1)数组

<?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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
	<bean id="别名" class="要注入对象的全类名">
        <property  name="属性名">
            <array>
                <value>值1</value>
                <value>值2</value>
                    .......
                <value>值n</value>
            </array>
       	</property>
    </bean>
</beans>

(2)List集合

<?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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
	<bean id="别名" class="全类名">
        <property  name="属性名">
            <list>
                <value>值1</value>
                <value>值2</value>
                    .......
                <value>值n</value>
            </list>
        </property>
    </bean>
</beans>

(3)Set集合

<?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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
	<bean id="别名" class="全类名">
       	<property name="属性名">
            <set>
                <value>值1</value>
                <value>值2</value>
                    .......
                <value>值n</value>
            </set>
        </property>
    </bean>
</beans>

(4)Map集合

<?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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
	<bean id="别名" class="全类名">
        <property name="属性名">
            <map>
                <entry key="键1" value="值1" />
                <entry key="键2" value="值2" />
                    .......
                <entry key="键n" value="值n"/>
            </map>
        </property>
    </bean>
</beans>

(5)Property

<?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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
	<bean id="别名" class="全类名">
        <property name="属性名">
            <props>
                <prop key="键1">值1</prop>
                <prop key="键2">值2</prop>
                		.......
                <prop key="键n">值n</prop>
            </props>
        </property>
    </bean>
</beans>
9、工厂模式注入
<?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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
	<bean id="工厂别名" class="工厂类全类名"></bean>
    <bean id="工厂方法别名" factory-bean="工厂别名" factory-method="工厂方法"></bean>
</beans>

注:通过Spring工厂模式注入时,被调用的方法不能是static

五、AoP(代理)

1、代理的概念

​ 代理是在实现原功能的基础上,对原功能的增强。

​ 面向切面编程,即面向我们的关注面,不能让非关注面影响到我们的关注面。而现实场景中非关注面又必不可少,例如获取资源、释放资源、处理异常、记录日志等,太多的非关切面会让关切面的代码变得杂糅,难以维护。此时面向切面编程便是解决此问题的方案,减少非关切面的东西,让我们只专注于核心业务代码

2、静态代理

​ (1)静态代理需要手动来创建代理类,在代理类中重写原功能的方法的方式对原功能进行加强,其优点为可定制性高,即想增强什么方法就增强什么方法。

public class CalculationProxy implements calculation {
    Calculation calculation=null;

    public void setCalculation(calculation calculation){
        this.calculation=calculation;
    }

    @Override
    public Integer sub(Integer a, Integer b) {
        long begin = System.currentTimeMillis();
        lazy();
        Integer sub = calculation.sub(a, b);
        long end = System.currentTimeMillis();
        System.out.println("耗时"+(end-begin)+"毫秒");
        return sub;
    }

    @Override
    public Integer plus(Integer a, Integer b) {
        long begin = System.currentTimeMillis();
        lazy();
        Integer plus = calculation.plus(a, b);
        long end = System.currentTimeMillis();
        System.out.println("耗时"+(end-begin)+"毫秒");
        return plus;
    }

    public void lazy(){
        Random random=new Random();
        try {
            Thread.sleep(random.nextInt(1000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

​ 上述代码在进行加减运算功能的基础上添加了计算耗时的功能

注入:1、代理的实质其实是创建一个代理对象,在代理对象中重写需要代理的方法从而实现功能增强的效果

2、工厂类创建的实质是创建代理对象,调用的也是代理对象的代理方法,其对原方法没有改变

​ (2)静态代理的缺点:若需要代理的方法越多,则需要手写的代码越多。

3、JDK代理

​ (1)JDK代理是一种动态代理,用JDK提供的类创建代理类,只需要写一个方法即可代理所有需要代理的方法。

public class Factory {
    public UserService getUserService(){
        UserService us=new UserServiceImpl();
        //设置切点,第一个参数为工厂类的类加载器,第二个参数为被代理对象的接口,第三个参数为切面方法
        UserService myUs=(UserService) Proxy.newProxyInstance(Factory.class.getClassLoader(), us.getClass().getInterfaces(), new InvocationHandler() {
            //切面方法
            @Override
            //o为代理对象,method为被代理的方法,objects为被代理方法的参数列表
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                MyAspect.before();
                Object invoke = method.invoke(us, objects);
                System.out.println(invoke);
                MyAspect.after();
                return invoke;
            }
        });
        //返回的是代理对象
        return myUs;
    }
}

​ (2)调用

public void test(){
        ApplicationContext ac=new ClassPathXmlApplicationContext("jdkproxy.xml");
    	//通过Spring工厂注入一个代理对象
        UserService userService = ac.getBean("userService", UserService.class);
    	//通过代理对象调用代理方法
        userService.add();
        userService.delete(new User(2,"大佬",12.6));
    }

注:被动态代理的对象需要接口们,因此被动态代理的对象一定是实现类,且只能代理被实现的方法!

​ (3)JDK代理的缺点

​ 侵入性强,需要写的代码代码还是太多

4、cglib代理

​ (1)cglib是一种动态代理,用Spring中framework提供类创建代理对象。

public class Factory {
    public UserService getUserService(){
        Enhancer enhancer=new Enhancer();
        //设置切点
        enhancer.setSuperclass(UserService.class);
        enhancer.setCallback(new MethodInterceptor() {
            //切面方法
            @Override
            //o为代理方法,method为被代理的方法,objects为参数列表,methodProxy为被代理的方法的代理方法
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                MyAspect.before();
                Object invoke = method.invoke(new UserServiceImpl(), objects);
                System.out.println(invoke);
                MyAspect.after();
                return invoke;
            }
        });
        //返回代理对象
        return (UserService) enhancer.create();
    }
}

​ (2)cglib代理的缺点

​ 没有解决JDK代理侵入性强的问题,代码相对jdk代理来说少了一点,但还是太多

5、ProxyFactoryBean代理

​ (1)ProxyFactoryBean代理是Spring代理,即将代理对象交由Spring管理,又容器注入一个代理对象;从而解决了侵入性强与代码量过多的问题。

​ Spring的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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
	//定义serviceImpl的bean对象
    <bean id="userService" class="com.qf.service.impl.UserServiceImpl"></bean>
	//设置拦截器
    <bean id="pp" class="com.qf.proxy_factory.MyAspect"></bean>
	//设置切点及切面
    <bean id="myFactory" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target" ref="userService"/>//设置切点
        <property name="interfaces" value="com.qf.service.UserService"/>//定义切点的接口们
        <property name="interceptorNames" value="pp"/>//定义切面
        <property name="optimize" value="true"/>//设置是否使用cglib代理
    </bean>

</beans>

​ 拦截器的实现

public class MyAspect implements MethodInterceptor {
    public void before(){
        System.out.println("这是前置条件");
    }

    public void after(){
        System.out.println("这是后置条件");
    }

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        before();
        Object proceed = invocation.proceed();
        System.out.println(proceed);
        after();
        return proceed;
    }
}

​ 调用

public class TestProxyFactoryBean {
    @Test
    public void test(){
        ApplicationContext ac=new ClassPathXmlApplicationContext("proxy_factory_bean.xml");
        //获取代理对象
        UserService factory = ac.getBean("myFactory", UserService.class);
        factory.add();
        factory.delete(new User(4,"老杨",12.5));
    }
}

注:1、拦截器需要实现MethodInterceptor接口的invoke方法

2、optimize是ProxyFactoryBean的祖先类的属性,其代表的含义是是否使用cglib代理

3、除了target是ref外,其他都是value;其中interceptorNames是获得到value后,找到其id为value的bean,通过反射调用其拦截器的方法。

(2)MethodInvocation类的说明

​ 其底层封装了切面所需要的数据,调用起来更为简洁。

(3)ProxyFactoryBean代理还存在的问题

​ ProxyFactoryBean的切点还不是很精准

6、proxy_target_class代理

(1)proxy_target_class代理也是将代理对象交由Spring容器进行注入,其代码量更简洁,且可定义切点规则,使切点更精确;调用时直接获取service实现类对象,在调用实现类对象方法是通过反射进行实现功能的增强

​ Spring的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">
    //定义serviceImpl的bean对象
    <bean id="proxy" class="com.qf.proxy_target.MyAspect"></bean>
	//定义拦截器的bean对象
    <bean id="userService" class="com.qf.service.impl.UserServiceImpl"></bean>
	//通过命名空间,设置切点及切面
    <aop:config proxy-target-class="true">//设置强制使用cglib代理
        //设置切点的规则
        <aop:pointcut id="point" expression="execution(* com.qf.service..*.*(..))"/>
        //设置切面
        <aop:advisor advice-ref="proxy" pointcut-ref="point"/>
    </aop:config>
</beans>

​ 拦截器实现

public class MyAspect implements MethodInterceptor {

    public void before(){
        System.out.println("这是前置条件");
    }

    public void after(){
        System.out.println("这是后置条件");
    }

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        before();
        Object proceed = invocation.proceed();
        System.out.println(proceed);
        after();
        return null;
    }
}

​ 调用

public class TestProxyTragetClasss {
    @Test
    public void test(){
        ApplicationContext ac=new ClassPathXmlApplicationContext("proxy_target_class.xml");
        //此时获取的代理对象是UserService
        UserService proxy = ac.getBean("userService", UserService.class);
        //调用代理对象的代理方法时通过反射调用
        proxy.add();
        proxy.delete(new User(5,"小王",1.25));
    }
}

注:此代理需要加入aspectjweaver依赖

	<dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
    <version>1.6.8</version>

(2)不足

​ 虽然切点更精确了,但切面的功能相对来说还是少了点,只有前置切面与后置切面两种

7、proxy_target_class增强代理

(1)、此代理比proxy_target_class代理的功能更多,具有前置、后置、环绕、返回值增强、异常增强的功能;其调用时也是获取serviceImpl对象,通过反射调用其拦截器的增强方法。

​ Spring的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="userService" class="com.qf.service.impl.UserServiceImpl"></bean>
    <bean id="proxy" class="com.qf.proxy_target_class_power.MyAspect"></bean>
    //设置切面与切点
    <aop:config proxy-target-class="true">
        <aop:aspect id="aspect" ref="proxy">
            //设置切点规则
            <aop:pointcut id="point" expression="execution(* com.qf.service..*.*(..))"/>
            <aop:before method="before" pointcut-ref="point"/>//设置前置切面
            <aop:after method="after" pointcut-ref="point"/>//设置后置切面
            <aop:around method="around" pointcut-ref="point"/>//设置环绕切面
            //设置返回值的切面,其returning的值必须要与拦截器中的参数一致
            <aop:after-returning method="haveReturn" pointcut-ref="point" returning="object"/>
            //设置异常的切面,其returning的值必须要与拦截器中的参数一致
            <aop:after-throwing method="throwException" pointcut-ref="point" throwing="throwable"/>
        </aop:aspect>
    </aop:config>
</beans>

​ 拦截器的实现

public class MyAspect {
	//前置切面
    public void before(){
        System.out.println("这是前置条件");
    }
	//后置切面
    public void after(){
        System.out.println("这是后置条件");
    }
	//环绕切面
    public void around(ProceedingJoinPoint joinPoint){
        try {
            System.out.println("这是环绕的前置条件");
            Object proceed = joinPoint.proceed();
            System.out.println("这是环绕的后置条件");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }
	//返回值切面
    public void haveReturn(JoinPoint joinPoint,Object object){
        System.out.println("我的返回值为"+object);
    }
	//异常切面
    public void throwException(JoinPoint joinPoint,Throwable throwable){
        System.out.println("我抛出的异常为"+throwable.getMessage());
    }

}

注:1、其需要什么切面就在Spring的xml文件中定义什么切面

2、返回值切面是当被增强的方法有返回值时才会对其进行增强,异常切面同理

3、环绕切面是在一个方法中即可定义前置切面也可定义后置切面,若同时具有前置切面与后置切面时,其调用的顺序为:前置切面->环绕前置切面->被增强的方法(返回值切面)->环绕的后置切面->后置切面

8、使用注解代理

(1)、使用注解动态代理可以更简便的进行动态代理,只需要在Spring的xml文件中设置好切点与切面后,将切点类与切面类通过<context:compont-scan base-package=“要扫描的包”/>标签扫描进Spring中,并在Aspect类中写需要的切面方法即可。调用时获得serviceImple代理类即可。

​ Spring的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 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">
    <context:component-scan base-package="com.qf.service"/>
    <context:component-scan base-package="com.qf.auto"/>
    <aop:aspectj-autoproxy/>
</beans>

​ 拦截器方法

package com.qf.auto;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class MyAspect {

    @Pointcut(value = "execution(* com.qf.service..*.*(..))")
    public void all(){

    }
    @Before("all()")
    public void before(){
        System.out.println("这是前置切面");
    }
    @After("all()")
    public void after(){
        System.out.println("这是后置切面");
    }
    @Around("all()")
    public void around(ProceedingJoinPoint joinPoint){
        try {
            System.out.println("环绕前置切面");
            Object proceed = joinPoint.proceed();
            System.out.println(proceed);
            System.out.println("环绕后置切面");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }
    @AfterReturning(value = "all()",returning = "obj")
    public void returing(JoinPoint joinPoint, Object obj){
        System.out.println("我的返回值切面为"+obj);
    }
    @AfterThrowing(value = "all()",throwing = "obj")
    public void throwing(JoinPoint joinPoint,Throwable obj){
        System.out.println("我的异常切面为"+obj.getMessage());
    }
}

​ ServiceImple方法的标签设置

package com.qf.service.impl;

import com.qf.pojo.User;
import com.qf.service.UserService;
import org.springframework.stereotype.Component;

@Component("userService")
public class UserServiceImpl implements UserService {
    @Override
    public User add() {
        return new User(1,"张杰",1.25);
    }

    @Override
    public Integer delete(User user) {
        System.out.println(user);
        return 250;
    }

}

注:1、需要注意的是返回值切面与异常切面方法的参数中的Joinpoint类的包,是org.aspectj.lang.JoinPoint包

​ 2、ServiceImpl中的Componet()注解中要加上其id值,getBean时也是获取的是此id值

3、Aspect类中要加入@Aspect标签

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值