spring学习2

Posted escapist

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring学习2相关的知识,希望对你有一定的参考价值。

使用注解配置spring

步骤:  

  1. 导包4(core/bean/context/spel)+1(logging)+spring-aop包(新版spring需要导入这个包)

  2. 为主配置文件引入新的命名空间(约束)  Context约束

  3. 开启使用注解代理配置文件

<context:component-scan base-package="com.domain">  指定扫描 com.domain包下面所有类的注解(同时会扫描子包里面的类)

  4. 在类中使用注解完成配置

@Component("user")public class User {
    private String name;
    private Integer age;
    
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "User [name=" + name + ", age=" + age + ", car=" + car + "]";
    }
}

 

将对象注册到容器

@Component(“user”) 

@Service(“user”)  service层

@Controller(“user”)  web层

@Repository(“user”)  dao层

本质上这四个功能都是一样  只是为了见名知意

 

修改对象的作用范围

@Scope(scopeName=”prototype”) 指定对象的作用范围         同样也是作用在实体上面

 

值类型注入

@Value("tom")
private String name;

通过反射来为Field赋值 ,但是这样破坏了封装性

 

通过set方法来赋值  推荐使用

@Value("24")
public void setAge(Integer age) {
    this.age = age;
}

 

引用类型注入

1.使用AutoWired 自动装配

@Component("user")
public class User {
    @Autowired
    private Car car;

        setCar/getCar ...
}

@Component
class Car{
    private String cName;
    private String color;
get/set ... } 注意:使用自动装配,被装配的字段 也要在容器有 可以没有名字

这种方式有一个坏处:如果匹配多个类型一致的对象,将无法选择具体注入哪一个对象

 

解决办法:使用 Qualifier("car")  通过该注解来告诉 spring容器自动装配哪个名称的对象

注意:Qualifier和AutoWired要一起使用

 

@Resource(name="car") 手动注入,指定注入哪个名称的对象

@Resource(name="car")
private Car car;

 

初始化 | 销毁方法

@PostConstruct                      // 在对象被创建以后调用   相当于配置文件中定义的init-method 
public void init() {
    System.out.println("init method");
}
    
@PreDestroy                       // 在对象被销毁前调用        destory-method
public void destory(){
    System.out.println("destory method");
}                                                

 

spring与junit整合测试

1.导包    4+2+aop+test

2.配置注解

@RunWith(SpringJUnit4ClassRunner.class)      // 帮我们创建容器
@ContextConfiguration("classpath:applicationContext.xml")  //指定创建容器时使用的配置文件
public class Student {
    
    @Value("wanglei")
    private String name;
    
    @Test
    public void test() {
        System.out.println(name);
    }
    
    @Value("24")
    private Integer age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
}

 

spring中的aop

aop思想介绍  横向重复代码 ,纵向抽取

例如:解决乱码问题   管理事务  action拦截器

 

spring中的aop概念 ------> spring能够为容器中管理的对象生成动态代理对象

以前我们要使用动态代理,需要自己调用下面的方法

Proxy.newProxyInstance(xx,xx,xx) 生成代理对象

现在spring能够帮助我们生成代理对象

 

spring实现aop的原理

 1.动态代理(优先) :   被代理对象必须要实现接口,才能产生代理对象,如果没有接口将不能使用动态代理技术。

 2.cglib代理(没有接口) : 第三方代理技术,cglib代理可以对任何类生成代理,代理的原理是对目标对象进行继承代理.

    但是如果目标对象被final修饰,那么该类无法被cglib代理.

步骤:

  1.创建service的接口是实现类

  

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

public class UserServiceIml implements UserService {
    public void save() {
        System.out.println("save");
    }
    public void add() {
        System.out.println("add");
    }
    public void delete() {
        System.out.println("delete");
    }
    public void find() {
        System.out.println("find");
    }
}

  2.使用cglib代理生成代理对象

public class Test implements MethodInterceptor{
    
    public UserService getService() {
        Enhancer en=new Enhancer();   //用于生成代理对象
        en.setSuperclass(UserServiceIml.class);//对谁设置代理
        en.setCallback(this); //代理要做什么
        UserService service = (UserService) en.create();//创建代理对象
        return service;
    }
    
    @Override           proxyObj 目标类的实例  method 目标类方法的反射实例   arg 参数  methodProxy 代理类实例            
    public Object intercept(Object proxyObj, Method method, Object[] arg, MethodProxy methodProxy) throws Throwable {
        System.out.println("打开事务!");
        Object returnValue = methodProxy.invokeSuper(proxyObj, arg);
        System.out.println("提交事务!");
        return returnValue;
    }    
}

   3.测试

public static void main(String[] args) {
        Test test = new Test();
        UserService service = test.getService();
        service.save();
}

 

AOP名词学习

Joinpoint(连接点):目标对象中,所有可以增强的方法

Pointcut(切入点): 目标对象,已经增强的方法

Advice(通知/增强):增强的代码

Target(目标对象): 被代理的对象

Weaving(织入):将通知应用到切入点的过程

Proxy(代理):将通知织入到目标对象之后,形成代理对象

Aspect(切面):切入点 + 通知

 

spring中的aop演示

 步骤:

1.导包4(core + bean + spel + context)+2  + 2(aop + aspect) + 2(allowiance + weaving)

        aop包 + aspect包 + aopalliance + weaver 

 

 

2.准备目标对象

 

用到spring2.5版本的jar文件,如果用jdk1.7可能会有问题

需要升级aspectj组件,即使用aspectj-1.8.2版本中提供jar文件提供

 

3.准备通知

     前置通知   目标方法运行之前调用

     后置通知(如果出现异常不会调用)  在目标方法运行之后调用

     环绕通知   在目标方法之前和之后都调用

     异常拦截通知:如果出现异常,就会调用

     后置通知(无论是否出现异常都会调用) :在目标方法运行之后调用

public class MyAdvice {
    //前置通知
    public void before() {
        System.out.println("前置通知");
    }
    //后置通知
    public void afterReturn() {
        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.配置进行织入,将通知织入目标对象中

    准备工作:导入AOP(约束)命名空间

    1.配置目标对象  将具体的实现类(而不是接口添加进来)   因为是为 实现类来创建代理对象

      <bean name="userService" class="..."></bean>

    2.配置通知对象

      <bean name="myAdvice" class="...">

    3.配置切入点

     <aop:pointcut expression="execution(* cn.itcast.service.*ServiceImpl.*(..))" id="pc"/>

execution有以下几种形式

public void cn.itcast.service.UserServiceImpl.save()  具体的某个方法
void cn.itcast.service.UserServiceImpl.save()   
* cn.itcast.service.UserServiceImpl.save()      任意返回值
* cn.itcast.service.UserServiceImpl.*()           任意方法名/任意返回值
* cn.itcast.service.*ServiceImpl.*(..)              任意参数/ 任意返回值/ 任意方法名
* cn.itcast.service..*ServiceImpl.*(..)       还会找这个下面的子包

<aop:config>
        <aop:pointcut expression="execution(* com.domin.*Service.*(..))" id="pc"/>  //表示拦截哪些方法
        <aop:aspect ref="advice">
            <aop:before method="before" 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:after-returning method="afterReturn" pointcut-ref="pc"/>
        </aop:aspect>
</aop:config>
<!-- 【拦截所有public方法】 -->
        <!--<aop:pointcut expression="execution(public * *(..))" id="pt"/>-->
        
        <!-- 【拦截所有save开头的方法 】 -->
        <!--<aop:pointcut expression="execution(* save*(..))" id="pt"/>-->
        
        <!-- 【拦截指定类的指定方法, 拦截时候一定要定位到方法】 -->
        <!--<aop:pointcut expression="execution(public * cn.itcast.g_pointcut.OrderDao.save(..))" id="pt"/>-->
        
        <!-- 【拦截指定类的所有方法】 -->
        <!--<aop:pointcut expression="execution(* cn.itcast.g_pointcut.UserDao.*(..))" id="pt"/>-->
        
        <!-- 【拦截指定包,以及其自包下所有类的所有方法】 -->
        <!--<aop:pointcut expression="execution(* cn..*.*(..))" id="pt"/>-->
        
        <!-- 【多个表达式】 -->
        <!--<aop:pointcut expression="execution(* cn.itcast.g_pointcut.UserDao.save()) || execution(* cn.itcast.g_pointcut.OrderDao.save())" id="pt"/>-->
        <!--<aop:pointcut expression="execution(* cn.itcast.g_pointcut.UserDao.save()) or execution(* cn.itcast.g_pointcut.OrderDao.save())" id="pt"/>-->
        <!-- 下面2个且关系的,没有意义 -->
        <!--<aop:pointcut expression="execution(* cn.itcast.g_pointcut.UserDao.save()) &amp;&amp; execution(* cn.itcast.g_pointcut.OrderDao.save())" id="pt"/>-->
        <!--<aop:pointcut expression="execution(* cn.itcast.g_pointcut.UserDao.save()) and execution(* cn.itcast.g_pointcut.OrderDao.save())" id="pt"/>-->
        
        <!-- 【取非值】 -->
        <!--<aop:pointcut expression="!execution(* cn.itcast.g_pointcut.OrderDao.save())" id="pt"/>-->
        <aop:pointcut expression=" not execution(* cn.itcast.g_pointcut.OrderDao.save())" id="pt"/>
        
        <!-- 切面 -->
        <aop:aspect ref="aop">
            <!-- 环绕通知 -->
            <aop:around method="around" pointcut-ref="pt"/>
        </aop:aspect>

 

调用顺序

1.没有发生异常的情况下

     前置通知
     这是环绕通知之前的部分
     save method
     这是环绕通知之后的部分
    后置通知(出现异常也会调用)
    后置通知(如果出现异常不会被调用)

2.发生异常的情况下  

    前置通知
    这是环绕通知之前的部分
    出现异常了
    后置通知(出现异常也会调用)

 

 注解配置实现动态代理

1.导包

2.配置

  同样需要加入  <bean name="userService" class="..."></bean>  和 <bean name="myAdvice" class="...">

3.使用注解来实现代理

4.在配置文件中加入 <aop:aspectj-autoproxy></aop:aspectj-autoproxy>  表示开启使用注解完成织入

5.测试

 

@Aspect                                                          指定一个类为切面类           

@Pointcut("execution(* cn.itcast.e_aop_anno.*.*(..))")  指定切入点表达式

@Before("pointCut_()")                                前置通知: 目标方法之前执行

@After("pointCut_()")                                   后置通知:目标方法之后执行(始终执行)

@AfterReturning("pointCut_()")             返回后通知: 执行方法结束前执行(异常不执行)

@AfterThrowing("pointCut_()")                  异常通知:  出现异常时候执行

@Around("pointCut_()")                               环绕通知: 环绕目标方法执行

@Component
@Aspect  // 指定当前类为切面类
public class Aop {

    // 指定切入点表单式: 拦截哪些方法; 即为哪些类生成代理对象
    
    @Pointcut("execution(* cn.itcast.e_aop_anno.*.*(..))")
    public void pointCut_(){
    }
    
    // 前置通知 : 在执行目标方法之前执行
    @Before("pointCut_()")
    public void begin(){
        System.out.println("开始事务/异常");
    }
    
    // 后置/最终通知:在执行目标方法之后执行  【无论是否出现异常最终都会执行】
    @After("pointCut_()")
    public void after(){
        System.out.println("提交事务/关闭");
    }
    
    // 返回后通知: 在调用目标方法结束后执行 【出现异常不执行】
    @AfterReturning("pointCut_()")
    public void afterReturning() {
        System.out.println("afterReturning()");
    }
    
    // 异常通知: 当目标方法执行异常时候执行此关注点代码
    @AfterThrowing("pointCut_()")
    public void afterThrowing(){
        System.out.println("afterThrowing()");
    }
    // 环绕通知:环绕目标方式执行
    @Around("pointCut_()")
    public void around(ProceedingJoinPoint pjp) throws Throwable{
        System.out.println("环绕前....");
        pjp.proceed();  // 执行目标方法
        System.out.println("环绕后....");
    }
}
<!-- 开启注解扫描 -->
    <context:component-scan base-package="cn.itcast.e_aop_anno"></context:component-scan>
    
    <!-- 开启aop注解方式 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy> 

 

Spring Web  Spring对web模块的支持。

            可以与struts整合,让struts的action创建交给spring

             spring mvc模式

Spring DAO  Spring 对jdbc操作的支持  【JdbcTemplate模板工具类】

Spring ORM  spring对orm的支持:

              既可以与hibernate整合,【session】

               也可以使用spring的对hibernate操作的封装

SpringEE   spring 对javaEE其他模块的支持

 

以上是关于spring学习2的主要内容,如果未能解决你的问题,请参考以下文章

Spring boot:thymeleaf 没有正确渲染片段

What's the difference between @Component, @Repository & @Service annotations in Spring?(代码片段

spring练习,在Eclipse搭建的Spring开发环境中,使用set注入方式,实现对象的依赖关系,通过ClassPathXmlApplicationContext实体类获取Bean对象(代码片段

Spring Rest 文档。片段生成时 UTF-8 中间字节无效 [重复]

Spring MVC 3.2 Thymeleaf Ajax 片段

IOS开发-OC学习-常用功能代码片段整理