发表于: 2017-11-29 23:11:18

1 599


今天完成得事情

1.研究Bean类型重复时得问题

类型一般时不会重复的,在同一个包中不能创建相同的类,如果在不同的包中创建,本质上已经是不同的类了,所以可以考虑用接口,将接口声明为一个bean,写两个实现类,再用@Autowired注解注入接口类型的bean

接口:

@Component
public interface A {
void print();
}

两个实现类:

@Component
public class A1 implements A{
   @Value("Hello")
   private String p1;
   @Value("World")
   private String p2;
   public void print(){
      System.out.println("this is A1: "+p1+" "+p2);
   }
}
@Component
public class A2 implements A{
   @Value("Hello")
   private String p1;
   @Value("spring")
   private String p2;
   public void print(){
      System.out.println("this is A2: "+p1+" "+p2);
   }
}

注入:

@Component
public class A4 {
   @Autowired
   A a;
   public void print(){
      a.print();
   }
}

测试:

@Test
public void TestA4(){
   A4 aa = context.getBean(A4.class);
   aa.print();
}

果然有报错:

意思是有两个相同类型类型的Bean


查阅之后,有两个解决方法:

可以设置首选bean,采用注解@Primary,当自动装配时,会首先找被@Primary标注的bean

@Component("aaa")
@Primary
public class A1 implements A{

测试结构:

通过

方法二,通过 @Qualifier注解,装配具有相应id的bean

@Component
public class A4 {
   @Autowired
   @Qualifier("aa")
   A a;

设置bean的id:

@Component("aa")
public class A2 implements A{

测试通过:

如果将bean的id也设置成相同的,应该还是会报错:

@Component("aaa")
public class A1 implements A{
@Component("aaa")
public class A2 implements A{
@Autowired
@Qualifier("aaa")
A a;

果然有报错:

Annotation-specified bean name 'aaa' for bean class [auto.A2] conflicts with existing, non-compatible bean definition of same name and class [auto.A1]

意思bean的名称有冲突

所以,采用@Autowired注解进行自动装配时,如果是相同类型的bean,就设置不同的id吧


2.又看了AOP

AOP中有几个术语

横切关注点:系统中的非核心业务的功能,如日志等,横切关注点可以被模块化为特殊的类,这些类被称为切面

通知:切面的工作被称为通知,定义了切面是什么以及何时使用,spring切面有5种类型的通知

1.前置通知

2.后置通知

3.返回通知

4.异常通知

5.环绕通知

连接点:连接点是程序执行过程种能够应用通知的所有的点

切点:切点定义了通知被应用的具体位置(在哪些连接点)

切面:切面和切点的结合,通知和切点共同定义了切面的全部内容,是什么,在何时,在何处

引入:利用引入可以向现有的类添加新的方法或属性

织入:springAOP在应用运行到相应的点时将切面织入


有两种方法配置切面:

1.在xml配置文件中配置:

目标类:

public class Hehe {
public void hello(){
System.out.println("this is aop xml");
   }
}

定义将要作为切面的类:

public class Cut {
public void before(){
System.out.println("this is before");
   }
}

在xml中定义切面:

<bean id="hehe" class="aopxml.Hehe"/>
<bean id="cut" class="aopxml.Cut"/>
<aop:config>
   <aop:aspect ref="cut">
      <aop:pointcut id="hello" expression="execution(* aopxml.Hehe.hello(..))"/>
       <aop:before pointcut-ref="hello"
           method="before"/>
   </aop:aspect>
</aop:config>

先将两个类声明为bean,然后用命名空间<aop:config>定义切面,<aop:aspect ref="cut">引用作为切面的类,

<aop:pointcut id="hello" expression="execution(* aopxml.Hehe.hello(..))"/>定义了切点,<aop:before pointcut-ref="hello" method="before"/>定义了通知类型为前置通知并应用方法“before”

测试:

@Test
public void testaopxml(){
   Hehe hehe =(Hehe) ap.getBean("hehe");
   hehe.hello();
}

结果


2.在Java代码中配置:

需要编写一个配置类,用于开启扫描:

@Configuration
@ComponentScan
@EnableAspectJAutoProxy
public class config {
}

@EnableAspectJAutoProxy用于启动自动代理功能

目标类和前面的相同,不过要注解为bean:

@Component
public class Haha {

定义切面:

@Component
@Aspect
public class Cut {


@Pointcut("execution(* aop.Haha.print(..))")
   public void cut(){
   }

   @Before("cut()")
   public void before(){
       System.out.println("this is before");
   }
}

@Aspect注解定义此类为bean,@Pointcut注解定义了一个切点,如果其他通知要用相同的切点,可以直接引用此注解下的方法,@Before("cut()")注解定义通知为前置通知,并引用前面的切点


还可以通过AOP为原有的类引入新的方法而不用对原有的类做任何的修改

先定义一个接口,以及接口的实现类:

public interface Hello {
void hello();
}
public class HelloImpl implements Hello{
public void hello(){
System.out.println("Hello JCY");
   }
}

在切面类中添加:

@DeclareParents(value = "aop.Haha+",defaultImpl = HelloImpl.class)
public Hello hello;

value = "aop.Haha+"表示为Haha类及其子类添加方法或属性,其具体的实现由defaultImpl = HelloImpl.class定义,表示添加的是HelloImpl类中的方法和属性,public Hello hello 声明接口类型

测试:

@Test
   public void testaop(){
       Hello haha =(Hello) context.getBean(Haha.class);
       haha.hello();
   }

成功:

在没有对原有的类进行任何修改的情况下,实现了新方法的添加,很神奇


明天的计划

再看看以前遗漏的地方

研究一下需求文档


遇到的问题



收获

对AOP又有了一些理解


返回列表 返回列表
评论

    分享到