Spring 简介(02)

Spring 简介(02)

7.Spring EL 表达式(了解)

Spring Expression Language,Spring表达式语言,简称SpEL。支持运行时查询并可以操作对象图。

和JSP页面上的EL表达式,SpEL根据JavaBean风格的getXxx()、setXxx()方法定义的属性访问对象图,完全符合我们熟悉的操作习惯。

7.1 基本语法

SpEL使用**#{…}**作为定界符,所有在大框号中的字符都将被认为是SpEL表达式。

7.2 使用字面值

7.3 引用其他bean

7.4 引用其他bean的属性值作为自己某个属性的值

7.5 调用非静态方法

7.6 调用非静态方法

    <bean id="car" class="com.atguigu.pojo.Car">
        <property name="name" value="粪叉子"/>
        <property name="carNo" value="京A43242"/>
    </bean>
    <bean id="person" class="com.atguigu.pojo.Person">
        <property name="id" value="#{1}"/>
<!--        <property name="name" value="#{laoxu}"/>-->
<!--        <property name="name" value="#{'laoxu'}"/>-->
        <!-- 调用静态方法 -->
<!--        <property name="name" value="#{car.noStaticFun()}"/>-->
        <!-- 调用非静态方法 -->
        <property name="name" value="#{T(com.atguigu.pojo.Car).staticFun()}"/>
        <property name="salary" value="#{342.2}"/>
        <property name="car" value="#{car}"/>
    </bean>

7.7 运算符

①算术运算符:+、-、*、/、%、^

②字符串连接:+

③比较运算符:<、>、==、<=、>=、lt、gt、eq、le、ge

④逻辑运算符:and, or, not, |

⑤三目运算符:判断条件?判断结果为true时的取值:判断结果为false时的取值

⑥正则表达式:matches

8.注解功能(重点)

8.1 注解Dao Service Controller组件

实验32 : 通过注解分别创建Dao , Service , Controller

Spring 配置中bean的常用注解有

@Component 配置Web层 , Service层 , Dao层之外的对象

@Controller 配置Web层的组件

@Service 配置Service层

@Repository 配置Dao层

@Scope 配置Bean的作用域(单例 , 多例),用于类上 , 也可以用 于方法上, 当前方法必须有@Bean

@PostConstruct init-method

@PreDestory destory-method

@Value(“abc”) 给基本类型注入

@Value("${user}") 读取配置文件中的key得到Value给基本类型注入

@Value("${user:root}") 读取配置文件中的key如果没有key , 将root进行 注入

@Configuraction 表明当前类是一个配置文件类

@ComponentScan(basePackages={}) 扫描其他包下的注解

@Import 导入其他配置文件类

@Bean 将当前方法返回值放入容器内 , bean的id是方法名

代码 :

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


    <!-- 扫描其他注册的包 -->
    <context:component-scan base-package="com.atguigu"/>
</beans>

controller :

import org.springframework.stereotype.Controller;

/**
 *  @Controller 注解的作用是
 *  相当于 <bean class="com.atguigu.controller.PersonController" id="personController"/>
 */
@Controller
public class PersonController {
}

dao :

/**
 *  @Repository 注解的作用是 :
 *      相当于<bean = "com.atguigu.pojo.Impl.PersonDaoImpl" id = "personDaoImpl"/>
 */
@Repository
public class PersonDaoImpl implements PersonDao {
}

pojo :

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
/**
 *  @Component : 注解的作用是:
 *      相当于 : <bean class="com.atguigu.pojo.Person" id="person">
 *
 *  @Scope("prototype")      prototype : 多例
 *  @Scope("singleton")      singleton : 单例     默认
 */
@Component
@Scope("singleton")
public class Person {
}

service :

import com.atguigu.service.PersonService;
import org.springframework.stereotype.Service;

/**
 *  @Service 注解的作用是 :
 *      相当于<bean class="com.atguigu.service.Impl.PersonServiceImpl" id="personServiceImpl"/>
 */
@Service
public class PersonServiceImpl implements PersonService {
}

8.2 指定扫包时过滤的内容

实验33:使用context:include-filter指定扫描包时要包含的类

实验34:使用context:exclude-filter指定扫描包时不包含的类

​ <context:include-filter /> 设置包含的内容

注意:通常需要与use-default-filters属性配合使用才能够达到“仅包含某些组件”这样的效果。即:通过将use-default-filters属性设置为false

​ <context:exclude-filter /> 设置排除的内容

类别示例说明
annotationcom.atguigu.XxxAnnotation过滤所有标注了XxxAnnotation的类。这个规则根据目标组件是否标注了指定类型的注解进行过滤
assignablecom.atguigu.BaseXxx过滤所有BaseXxx类的子类。这个规则根据目标组件是否是指定类型的子类的方式进行过滤。
aspectjcom.atguigu.*Service+所有类名是以Service结束的,或这样的类的子类。这个规则根据AspectJ表达式进行过滤。
regexcom.atguigu.anno.*所有com.atguigu.anno包下的类。这个规则根据正则表达式匹配到的类名进行过滤。
customcom.atguigu.XxxTypeFilter使用XxxTypeFilter类通过编码的方式自定义过滤规则。该类必须实现org.springframework.core.type.filter.TypeFilter接口

自定义排除 :

  <!--
        context:component-scan 配置包扫描
            base-package="com" 指定要扫描哪个包,以及它的子包都会扫描
    -->
    <context:component-scan base-package="com.atguigu">

        <!--
            type="annotation" 排除过滤 排除注解, 并且包含子注解
            type : 是指过滤的类型
            expression : 过滤的表达式
        -->

        <context:exclude-filter type="annotation"
                                expression="org.springframework.stereotype.Repository"/>
    </context:component-scan>

</beans>

自定义包含 :

<!--
    context:component-scan 配置包扫描
        base-package="com" 指定要扫描哪个包,以及它的子包都会扫描
-->
<context:component-scan base-package="com.atguigu" use-default-filters="false">

    <!--
        context:include-filter 标签是自定义包含 , 必须use-default-filters="false"一起使用
        type="annotation" 排除过滤
        expression : 过滤的表达式
    -->

    <context:include-filter type="annotation"
                            expression="org.springframework.stereotype.Controller"/>

</context:component-scan>

注:

1 . @Controller @Service 和 @Repository 都继承了 Component

8.3 使用注解@Autowrite自动装配

实验35:使用@Autowired注解实现根据类型实现自动装配★

@Autowired 注解 会自动的根据标注的对象类型在Spring容器中查找相对应的类。如果找到,就自动装配。

使用@Autowired注解,不需要get/set方法

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;



/**
 *  @Service 注解的作用是 :
 *      相当于<bean class="com.atguigu.service.Impl.PersonServiceImpl" id="personServiceImpl"/>
 */
@Service
public class PersonServiceImpl implements PersonService {


    /**
     *  @Autowired : 将容器中bean给变量赋值
     *      1. 它会先从Spring容器中按类型找到并注入
     */

    @Autowired(required = false)
    private PersonDao personDao;

    @Override
    public String toString() {
        return "PersonServiceImpl{" +
                "personDao=" + personDao +
                '}';
    }
}

8.4 多个同类的bean如何自动装配

实验36:如果资源类型的bean不止一个,默认根据@Autowired注解标记的成员变量名作为id查找bean,进行装配★

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

/**
 *  @Service 注解的作用是 :
 *      相当于<bean class="com.atguigu.service.Impl.PersonServiceImpl" id="personServiceImpl"/>
 */
@Service
public class PersonServiceImpl implements PersonService {


    /**
     *  @Autowired : 将容器中bean给变量赋值
     *      1. 它会先从Spring容器中按类型找到并注入
     *      2. 当发现查找多个时候用 @Qualifier("personDaoImpl") 进行标识
     *          或者用@Resource(name = "personDaoImpl") 进行标识
     *
     */

    @Autowired(required = false)
    @Qualifier("personDaoImpl1")
    private PersonDao personDao;

/*    @Resource(name = "personDaoImpl")
    private PersonDao personDao;*/

    @Override
    public String toString() {
        return "PersonServiceImpl{" +
                "personDao=" + personDao +
                '}';
    }
}

8.5 使用@Qualifier装配指定的id的bean对象

实验37:如果根据成员变量名作为id还是找不到bean,可以使用@Qualifier注解明确指定目标bean的id★

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;



/**
 *  @Service 注解的作用是 :
 *      相当于<bean class="com.atguigu.service.Impl.PersonServiceImpl" id="personServiceImpl"/>
 */
@Service
public class PersonServiceImpl implements PersonService {

    /**
     *  @Autowired : 将容器中bean给变量赋值
     *      1. 它会先从Spring容器中按类型找到并注入
     *      2. 当发现查找多个时候用 @Qualifier("personDaoImpl") 进行标识
     *          或者用@Resource(name = "personDaoImpl") 进行标识
     *
     */

    @Autowired(required = false)
    @Qualifier("personDaoImpl")
    private PersonDao personDao;

    @Override
    public String toString() {
        return "PersonServiceImpl{" +
                "personDao=" + personDao +
                '}';
    }
}

8.6 @Autowired注解的required属性作用

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

/**
 *  @Service 注解的作用是 :
 *      相当于<bean class="com.atguigu.service.Impl.PersonServiceImpl" id="personServiceImpl"/>
 */
@Service
public class PersonServiceImpl implements PersonService {

    /**
     *  @Autowired : 将容器中bean给变量赋值
     *      1. 它会先从Spring容器中按类型找到并注入
     *      2. 当发现查找多个时候用 @Qualifier("personDaoImpl") 进行标识
     *          或者用@Resource(name = "personDaoImpl") 进行标识
     *      3. 当 @Qualifier("personDaoImpl1") 可以用@Autowired(required = false) 进行标识允许为null
     *
     */

    @Autowired(required = false)
    @Qualifier("personDaoImpl1")
    private PersonDao personDao;

/*    @Resource(name = "personDaoImpl")
    private PersonDao personDao;*/

    @Override
    public String toString() {
        return "PersonServiceImpl{" +
                "personDao=" + personDao +
                '}';
    }
}

8.7 @AutoWired和@Qualifier在方法上使用

实验38:在方法的形参位置使用@Qualifier注解

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
/**
 *  @Service 注解的作用是 :
 *      相当于<bean class="com.atguigu.service.Impl.PersonServiceImpl" id="personServiceImpl"/>
 */
@Service
public class PersonServiceImpl implements PersonService {

    /**
     *  @Autowired : 将容器中bean给变量赋值
     *      1. 它会先从Spring容器中按类型找到并注入
     *      2. 当发现查找多个时候用 @Qualifier("personDaoImpl") 进行标识
     *          或者用@Resource(name = "personDaoImpl") 进行标识
     *      3. 当 @Qualifier("personDaoImpl1") 可以用@Autowired(required = false) 进行标识允许为null
     *
     */

    @Autowired(required = false)
    @Qualifier("personDaoImpl")
    private PersonDao personDao;

/*    @Resource(name = "personDaoImpl")
    private PersonDao personDao;*/

    /**
     * @Autowired 修饰在方法上会在当前bean初始化后执行
     * 被@Autowired 修饰的方法的参数 , 会自定注入 , (参数会自动去容器中查找类型相同的id)
     *      1:当有多个参数是,匹配变量名称 与bean 的id
     *      2:@Qualifier("personDaoImpl")可以写在方法的参数中,去指定bean的id给参数注入
     */
    @Autowired
    public void show(@Qualifier("personDaoImpl") PersonDao personDao){
        System.out.println("show() 方法执行" + personDao);
    }

    @Override
    public String toString() {
        return "PersonServiceImpl{" +
                "personDao=" + personDao +
                '}';
    }
}

8.8 Spring的专有测试

@ContextConfiguration 配置Spring容器需要的配置文件路径

@RunWith 配置使用Spring的扩展junit测试

官方觉得使用Junit测试在编写测试代码的时候,过于繁锁。为了方便测试,并且很好的使用上Spring的一些特性和功能。就对

Junit测试进行了扩展。

1 先导入Spring对junit扩展后的jar包

2 配置两个注解

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 表示使用Spring 扩展的Junit测试类来测试代码
 * @ContextConfiguration : 注解的作用是指定Spring容器需要的配置文件路径
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:bean.xml")
public class SpringTest {

    @Autowired
    private PersonService personService;

    @Test
    public void test(){
        System.err.println(personService);
    }
}

8.9 纯注解

配置

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.*;
/**
 * @Configuration == 当前类就是一个Spring的配置文件去使用
 * @ComponentScan == <context:comp-scan></context:comp-scan>
 * @Import == <import resource =""/> 导入其它配置文件类
 * @PropertySource:加载外置properties配置文件 <context:property-placeholder></context:property-placeholder>
 *
 */
@Configuration
@ComponentScan(basePackages = {"com.atguigu"})
@Import({SpringConfig01.class})
@PropertySource(value = "classpath:jdbc.properties")
public class  SpringConfig {


    /*
     *  @Value("${读取配置文件的key}") 给变量注入
     *  写字符串给变量注入
     */
    @Value("${user}")
    private String name;

    /**
     * jdbc.password 配置文件的key,当读不到的时候,将root给变量注入
     */
    @Value("${password:root}")
    private String password;

    /**
     * <bean id = "" class = ""></bean> 
     * @Bean : 将当前方法的返回值放入容器中 , bean的id是 当前方法名首字母小写
     * @Bean("abc") : 当前bean的id 是 abc
     * @Scope : 还可以指定bean的作用域
     * @Bean : 修饰的方法也会进行自动注入
     * @param personDao
     * @return
     */
    @Bean
    public Person person(@Qualifier("personDaoImpl") PersonDao personDao){
        System.out.println("name :" + name);
        System.out.println("password : " + password);
        return new Person();

    }
}

测试 :

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 表示使用Spring 扩展的Junit测试类来测试代码
 * @ContextConfiguration : 注解的作用是指定Spring容器需要的配置文件路径
 * classes : 放入配置文件类
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class SpringTest {

    @Autowired
    private PersonService personService;

    @Autowired
    private Person person;

    @Test
    public void test(){
//        System.err.println(personService);
        System.err.println(person);
    }

}

9.AOP切面编程

9.1 什么是AOP

AOP是面向切面编程。全称:Aspect Oriented Programming

面向切面编程指的是:程序是运行期间,动态地将某段代码插入到原来方法代码的某些位置中。这就叫面向切面编程。

9.2 一个简单计算数功能加日记

interface :

package com.atguigu.service;

public interface Calculation {
    int add(int num1, int num2);

    int add(int num1, int num2, int num3);

    int div(int num1, int num2);
}

Calculator 实现类接口:

package com.atguigu.service.Impl;

import com.atguigu.service.Calculation;
import com.atguigu.util.LogUtils;

public class Calculator implements Calculation {
    @Override
    public int add(int num1, int num2) {
        int result = 0;
       try {
           LogUtils.logBefore("add",num1 ,num2);
           result = num1 + num2;
           LogUtils.logAfterReturning("add",result);
       }catch (Exception e){
           LogUtils.logAfterThrowing("add",e);
       }
        return result;
    }

    @Override
    public int add(int num1, int num2, int num3) {
        int result = 0;
        try {
            LogUtils.logBefore("add",num1,num2,num3);
            result = num1 + num2 + num3;
            LogUtils.logAfterReturning("add",result);
        } catch (Exception e){
            LogUtils.logAfterThrowing("add",e);
        }
        return result;
    }

    @Override
    public int div(int num1, int num2) {
        int result = 0;
        try {
            LogUtils.logBefore("div",num1,num2);
            result = num1 / num2;
            LogUtils.logAfterReturning("div",result);
        } catch (Exception e){
            e.printStackTrace();
            LogUtils.logAfterThrowing("div",e);

        }
        return result;
    }
}

util:

package com.atguigu.util;

import java.util.Arrays;

public class LogUtils {

    public static void logBefore(String method, Object... args) {
        System.out.println(" 当前运算是 " + method + "  , 参数是: " + Arrays.asList(args));
    }

    public static void logAfterReturning(String method, Object result) {
        System.out.println(" 当前运算是 " + method + "  , 结果是: " + result);
    }

    public static void logAfterThrowing(String method, Exception e) {
        System.out.println(" 当前运算是 " + method + "  , 抛的异常是: " + e);
    }

}

test :

package com.atguigu.test;

import com.atguigu.service.Calculation;
import com.atguigu.service.Impl.Calculator;
public class ProxyTest {

    public static void main(String[] args) {
        Calculation calculation = new Calculator();
//        calculation.add(1 , 1);
        calculation.div(1,0);
    }
}

9.3 使用代理实现日记

9.3.1 使用jdk动态代理统一日记

必须要有接口

package com.atguigu.service;

public interface Calculation {
    int add(int num1, int num2);

    int add(int num1, int num2, int num3);

    int div(int num1, int num2);
}

接口实现类 :

package com.atguigu.service.Impl;

import com.atguigu.service.Calculation;
import com.atguigu.util.LogUtils;

public class Calculator implements Calculation {
    @Override
    public int add(int num1, int num2) {
        int result = 0;
        result = num1 + num2;
        return result;
    }

    @Override
    public int add(int num1, int num2, int num3) {
        int result = 0;
        result = num1 + num2 + num3;
        return result;
    }

    @Override
    public int div(int num1, int num2) {
        int result = 0;
        result = num1 / num2;
        return result;
    }
}

jdkProxy

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class JdkProxy {

    public static Object createProxy(Object object){
        /**
         * jdk动态代理:
         * 租房子:
         * 租客======>>目标
         * 中介======>>代理
         * 租房完毕:=======整个过程:代理过程
         * 房东
         * 要有接口
         *  ClassLoader loader,   类加载器
         *  Class<?>[] interfaces, 所有目标和代理对象的实现类接口集合
         *  InvocationHandler h     代理增强接口
         *
         */
        return Proxy.newProxyInstance(
                object.getClass().getClassLoader(),
                object.getClass().getInterfaces(),
                /**
                 * @param proxy     第一个参数,是代理对象实例
                 * @param method    第二个参数,它是调用方法的反射对象
                 * @param args      第三个参数,调用代理方法时传递进来的实参
                 * @return       @return InvocationHandler接口的 invoke() 方法的返回值,就是代理对象方法的返回值.
                 */
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        Object o = null;
                        try {
                            // 做一些增强操作
                            LogUtils.logBefore(method.getName(),args);
                            // 目标方法
                            o = method.invoke(object, args);
                            LogUtils.logAfterReturning(method.getName(),o);

                        } catch (Exception e) {
                            e.printStackTrace();
                            LogUtils.logAfterThrowing(method.getName(),e);
                        }
                        return o;
                    }
                }
        );
    }
}

test:

public class Test {
    public static void main(String[] args) {
        Calculation calculation = new Calculator();
//        calculation.add(1,2);
//        calculation.div(1,0);
        Calculation calculationProxy = (Calculation) JdkProxy.createProxy(calculation);
        calculationProxy.div(1 ,0);
    }

}

优点:这种方式已经解决我们前面所有日记需要的问题。非常的灵活(将公用的业务逻辑抽去出来进行重用)。而且可以方便的在后期进行维护和升级。

缺点:当然使用jdk动态代理,需要有接口。如果没有接口。就无法使用jdk动态代理,cglib代理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值