Spring 入门2

1 使用注解方式

1.1 配置applicationContext

添加xmlns:context="http://www.springframework.org/schema/context"约束,配置扫描包的路径

<!-- 指定扫描com.ibso.bean报下的所有类中的注解.
     注意:扫描包时.会扫描指定报下的所有子孙包
 -->
<context:component-scan base-package="com.ibso.bean"></context:component-scan>

1.2 创建相关类

创建user类如下

//<bean name="user" class="cn.itcast.bean.User"  />
//@Component("user")
//  @Service("user") // service层
//  @Controller("user") // web层
    @Repository("user")// dao层
//指定对象的作用范围
@Scope(scopeName="singleton")
public class User {
    private String name;
    @Value("18")
    private Integer age;
    
    //@Autowired //自动装配
    //问题:如果匹配多个类型一致的对象.将无法选择具体注入哪一个对象.
    //@Qualifier("car2")//使用@Qualifier注解告诉spring容器自动装配哪个名称的对象
    
    @Resource(name="car")//手动注入,指定注入哪个名称的对象
    private Car car;

......
    @PostConstruct //在对象被创建后调用.init-method
    public void init(){
        System.out.println("我是初始化方法!");
    }
    @PreDestroy //在销毁之前调用.destory-method
    public void destory(){
        System.out.println("我是销毁方法!");
    }
......

1.2.1 @Component

组件,作用在类上,相当于<bean name="user" class="cn.itcast.bean.User"/>
Spring 中提供 @Component 的三个衍生注解 ,这三个注解是为了让标类本身的用途清晰:( 功能目前来讲是一致的 )

  • @Controller :WEB 层
  • @Service :业务层
  • @Repository :持久层

1.2.2 @scope

指定对象的作用范围,@Scope(scopeName="singleton")

1.2.3 属性注入

@Value :用于注入普通类型 .
@Autowired :自动装配 :
* 默认按类型进行装配 .
* 按名称注入 : @Qualifier: 强制使用名称注入 .
@Resource 相当于 : * @Autowired 和@Qualifier 一起使用 .

1.2.4 生命周期

@PostConstruct:相当于init-method
@PreDestroy:相当于destroy-method

1.2.5 注解与xml方式比较

2 Spring Junit 测试

引入spring-test包,指定@RunWith(SpringJUnit4ClassRunner.class)junit将会为我们创建spring容器,@ContextConfiguration制定了配置文件,@Resource(name="user")将bean对象注入到框架中来

//帮我们创建容器
@RunWith(SpringJUnit4ClassRunner.class)
//指定创建容器时使用哪个配置文件
@ContextConfiguration("classpath:applicationContext.xml")
public class Demo {
    //将名为user的对象注入到u变量中
    @Resource(name="user")
    private User u;
    
    @Test
    public void fun1(){     
        System.out.println(u);      
    }   
    @Test
    public void fun2(){     
        System.out.println(u);      
    }   
    @Test
    public void fun3(){     
        System.out.println(u);
    }
}

3 AOP

3.1 AOP思想介绍

AOP思想:横向重复,纵向抽取。
AOP对程序进行增强,不修改源码的情况下,AOP可以进行权限校验,日志记录,性能监控,事务控制.
例如在多个service中,每个都要解决乱码问题,Filter的出现可以切入到所有service层,在Filter中直接解决乱码问题
再比如多个service中,每个都需要管理事务,通过InovationHandler可以统一管理事务
newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

3.2 Spring AOP

Spring能为容器中管理的对象生产动态代理对象
以前使用动态代理,我们需要手动调用Proxy.newProxyInstance(x,x,x)生成代理对象
Spring的AOP的底层用使用两种代理机制:
* JDK动态代理:针对实现了接口的类产生代理,被代理对象必须要实现接口
* Cglib动态代理:针对没有实现接口的类产生代理,生成当前类的子类对象,如果对象被final修饰将无法代理
动态代理实现
创建interface

public interface UserService {
    void save();
    void delete();
    void update();
    void find();
}

创建实现类

public class UserServiceImpl implements UserService {
    @Override
    public void save() {
        System.out.println("保存用户!");
        //int i = 1/0;
    }
    @Override
    public void delete() {
        System.out.println("删除用户!");
    }
    @Override
    public void update() {
        System.out.println("更新用户!");
    }
    @Override
    public void find() {
        System.out.println("查找用户!");
    }
}

JDK动态代理实现,创建UserServiceProxyFactory实现InvocationHandler接口,getUserServiceProxy方法创建代理对象,重写invoke方法,method.invoke(us, arg2);将调用原方法,在这段代码前后可以添加增强的代码

public class UserServiceProxyFactory implements InvocationHandler {
    
    public UserServiceProxyFactory(UserService us) {
        super();
        this.us = us;
    }
    private UserService us; 
    public UserService getUserServiceProxy(){
        //生成动态代理
        UserService usProxy = (UserService) Proxy.newProxyInstance(UserServiceProxyFactory.class.getClassLoader(),
                                    UserServiceImpl.class.getInterfaces(), 
                                    this);
        //返回
        return usProxy;     
    }
    @Override
    public Object invoke(Object arg0, Method method, Object[] arg2) throws Throwable {
        System.out.println("打开事务!");
        Object invoke = method.invoke(us, arg2);
        System.out.println("提交事务!");
        return invoke;
    }
}

编写测试方法,通过代理对象usProxy调用save方法

    @Test
    //动态代理
    public void fun1(){
        UserService us = new UserServiceImpl();
        UserServiceProxyFactory factory = new UserServiceProxyFactory(us);      
        UserService usProxy = factory.getUserServiceProxy();
        
        usProxy.save();
        //代理对象与被代理对象实现了相同的接口
        //代理对象 与 被代理对象没有继承关系
        System.out.println(usProxy instanceof UserServiceImpl );//false
    }

cglib代理实现,创建UserServiceProxyFactory实现MethodInterceptor接口,重写intercept方法,methodProxy.invokeSuper(prxoyobj, arg);调用原方法,在这段代码前后可以添加增强的代码

public class UserServiceProxyFactory2 implements MethodInterceptor {
    

    public UserService getUserServiceProxy(){
        
        Enhancer en = new Enhancer();//帮我们生成代理对象    
        en.setSuperclass(UserServiceImpl.class);//设置对谁进行代理      
        en.setCallback(this);//代理要做什么       
        UserService us = (UserService) en.create();//创建代理对象     
        return us;
    }
    @Override
    public Object intercept(Object prxoyobj, Method method, Object[] arg, MethodProxy methodProxy) throws Throwable {
        //打开事务
        System.out.println("打开事务!");
        //调用原有方法
        Object returnValue = methodProxy.invokeSuper(prxoyobj, arg);
        //提交事务
        System.out.println("提交事务!");        
        return returnValue;
    }
}

编写测试方法

    public void fun2(){     
        UserServiceProxyFactory2 factory = new UserServiceProxyFactory2();      
        UserService usProxy = factory.getUserServiceProxy();        
        usProxy.save();     
        //判断代理对象是否属于被代理对象类型
        //代理对象继承了被代理对象=>true
        System.out.println(usProxy instanceof UserServiceImpl );//true
    }

3.3 AOP名词介绍

Joinpoint(连接点):目标对象中所有可以增强的方法,如上面UserServiceImpl中的增删改查方法
Pointcut(切入点):目标对象中已经增强的方法,比如我们可以对增删改进行增强,这3个将作为切入点
Advice(通知/增强):增强的代码,如invoke方法前后的代码
Target(目标对象):被代理的对象,如上面UserServiceImpl
Weaving(织入):把增强应用切入点的过程.
Proxy(代理):将通知织入到目标对象后,形成代理对象
Aspect(切面): 是切入点和通知的结合

4 Spring AOP

4.1 准备目标对象

目标对象为上面UserServiceImpl对象

4.2 准备通知

创建通知类如下,处理不同类型通知

public class MyAdvice {
    
    //前置通知  
//      |-目标方法运行之前调用
    //后置通知(如果出现异常不会调用)
//      |-在目标方法运行之后调用
    //环绕通知
//      |-在目标方法之前和之后都调用
    //异常拦截通知
//      |-如果出现异常,就会调用
    //后置通知(无论是否出现 异常都会调用)
//      |-在目标方法运行之后调用
//----------------------------------------------------------------
    //前置通知
    public void before(){
        System.out.println("这是前置通知!!");
    }
    //后置通知
    public void afterReturning(){
        System.out.println("这是后置通知(如果出现异常不会调用)!!");
    }
    //环绕通知
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("这是环绕通知之前的部分!!");
        Object proceed = pjp.proceed();//调用目标方法
        System.out.println("这是环绕通知之后的部分!!");
        return proceed;
    }
    //异常通知
    public void afterException(){
        System.out.println("出事啦!出现异常了!!");
    }
    //后置通知
    public void after(){
        System.out.println("这是后置通知(出现异常也会调用)!!");
    }
}

4.3 将通知织入目标对象

配置application.xml,引入目标对象及通知对象的bean,

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" 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-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd ">

<!-- 准备工作: 导入aop(约束)命名空间 -->
<!-- 1.配置目标对象 -->
    <bean name="userService" class="cn.ibso.service.UserServiceImpl" ></bean>
<!-- 2.配置通知对象 -->
    <bean name="myAdvice" class="cn.ibso.springaop.MyAdvice" ></bean>
<!-- 3.配置将通知织入目标对象 -->
    <aop:config>
        <!-- 配置切入点  -->
        <aop:pointcut expression="execution(public void cn.itcast.service.UserServiceImpl.save())" id="pc"/>
        <aop:aspect ref="myAdvice" >
            <!-- 指定名为before方法作为前置通知 -->
            <aop:before method="before" pointcut-ref="pc" />
            <!-- 后置 -->
            <aop:after-returning method="afterReturning" pointcut-ref="pc" />
            <!-- 环绕通知 -->
            <aop:around method="around" pointcut-ref="pc" />
            <!-- 异常拦截通知 -->
            <aop:after-throwing method="afterException" pointcut-ref="pc"/>
            <!-- 后置 -->
            <aop:after method="after" pointcut-ref="pc"/>
        </aop:aspect>
    </aop:config>
</beans>

其中切入点的演化可以如下

            public void cn.ibso.service.UserServiceImpl.save() 
            void cn.ibso.service.UserServiceImpl.save()
            * cn.ibso.service.UserServiceImpl.save()
            * cn.ibso.service.UserServiceImpl.*()           
            * cn.ibso.service.*ServiceImpl.*(..)
            * cn.ibso.service..*ServiceImpl.*(..)

编写测试代码

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:cn/itcast/d_springaop/applicationContext.xml")
public class Demo {
    @Resource(name="userService")
    private UserService us;
    
    @Test
    public void fun1(){
        us.save();
    }
    
}

4.4 使用注解

在applicationContext中开启注解

<!-- 1.配置目标对象 -->
    <bean name="userService" class="cn.itcast.service.UserServiceImpl" ></bean>
<!-- 2.配置通知对象 -->
    <bean name="myAdvice" class="cn.itcast.e_annotationaop.MyAdvice" ></bean>
<!-- 3.开启使用注解完成织入 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

在通知类中以@Aspect表示通知类,

@Aspect
//表示该类是一个通知类
public class MyAdvice {
    @Pointcut("execution(* cn.ibso.service.*ServiceImpl.*(..))")
    public void pc(){}
    //前置通知
    //指定该方法是前置通知,并制定切入点
    @Before("MyAdvice.pc()")
    public void before(){
        System.out.println("这是前置通知!!");
    }
    //后置通知
    @AfterReturning("execution(* cn.ibso.service.*ServiceImpl.*(..))")
    public void afterReturning(){
        System.out.println("这是后置通知(如果出现异常不会调用)!!");
    }
    //环绕通知
    @Around("execution(* cn.ibso.service.*ServiceImpl.*(..))")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("这是环绕通知之前的部分!!");
        Object proceed = pjp.proceed();//调用目标方法
        System.out.println("这是环绕通知之后的部分!!");
        return proceed;
    }
    //异常通知
    @AfterThrowing("execution(* cn.ibso.service.*ServiceImpl.*(..))")
    public void afterException(){
        System.out.println("出事啦!出现异常了!!");
    }
    //后置通知
    @After("execution(* cn.ibso.service.*ServiceImpl.*(..))")
    public void after(){
        System.out.println("这是后置通知(出现异常也会调用)!!");
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,029评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,395评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,570评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,535评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,650评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,850评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,006评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,747评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,207评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,536评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,683评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,342评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,964评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,772评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,004评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,401评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,566评论 2 349

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,633评论 18 139
  • Spring Web MVC Spring Web MVC 是包含在 Spring 框架中的 Web 框架,建立于...
    Hsinwong阅读 22,358评论 1 92
  • 1.1 spring IoC容器和beans的简介 Spring 框架的最核心基础的功能是IoC(控制反转)容器,...
    simoscode阅读 6,702评论 2 22
  • 红藕香残玉簟秋 , 轻解罗裳 ,独上兰舟。云中谁寄锦书来,雁字回时,月满西楼。花自飘零水自流,一种相思,两处闲愁。...
    浅墨菱香阅读 338评论 0 2
  • 今年春节在永康过。永康今年不许燃放烟花爆竹,过年显得有点冷清。冷清的同时倒是让我静下心来读了几本书,还能简单...
    LynnRen阅读 622评论 0 1