Java EE 注解(一):Spring Annotation

这是个系列教程,看完这个,你对JavaEE注解,包括spring、hibernate,RESTFul web service ,JAXB, 以及junit注解将会有一个全面的了解。
英文原版网址在这里 我们不光是spring网站的搬运工@农夫山泉水,实际上,翻译过程中我保证准确同时,加入了自己的理解。

** Spring Annotations 列表: **

@Service
import org.springframework.stereotype.Service;

@Repository
import org.springframework.stereotype.Repository;

@Component
import org.springframework.stereotype.Component;

@Autowired
import org.springframework.beans.factory.annotation.Autowired;

@Transactional
import org.springframework.transaction.annotation.Transactional;

@Scope
import org.springframework.context.annotation.Scope;

以及

Spring MVC Annotations

@Controller
import org.springframework.stereotype.Controller;

@RequestMapping
import org.springframework.web.bind.annotation.RequestMapping;

@PathVariable
import org.springframework.web.bind.annotation.PathVariable;

@RequestParam
import org.springframework.web.bind.annotation.RequestParam;

@ModelAttribute
import org.springframework.web.bind.annotation.ModelAttribute;

@SessionAttributes
import org.springframework.web.bind.annotation.SessionAttributes;

Spring Security Annotations

@PreAuthorize
import org.springframework.security.access.prepost.PreAuthorize;

首先看一下一个典型的Java web项目结构:

Paste_Image.png

part1. Spring Annotations

@Service 用在所有业务逻辑代码类中,对应图中service package下的类

@Service
public class UserServiceImpl implements UserService{
}

@Repository用在领域类,对应三层的DAO层(数据库操作类),上图 的domain package:

@Repository
public interface UserRepo extends JpaRepository<User,Integer> {    
    User findByName(String name);
}

@Component用在其它组件(无法分类的,如工具类)
实际上,Component注解和其它注解有如下关系:

Paste_Image.png

@Autowired
自动织入其他bean到你的类中(Ioc,Spring精髓)

@Service
public class CompanyServiceImpl implements CompanyService {
 
  @Autowired
  private CompanyDAO companyDAO;
   
  ...
}

@Transactional
开启事务

@Service
public class CompanyServiceImpl implements CompanyService {
 
  @Autowired
  private CompanyDAO companyDAO;
 
//开启事务后,当此方法出错,数据将会回滚
//比如,连续添加10条数据,第7条出错,则最后一条都不会添加,若
//不加Trsanctional,则会添加6条
  @Transactional
  public Company saveName(Company comp) { 
    Company company = companyDAO.save(comp);
    return company;
  }
}

@Scope:
这个首先看一下spring中scope定义:

** scope概论**
spring中scope是一个非常关键的概念,简单说就是对象在spring容器(IOC容器)中的生命周期,也可以理解为对象在spring容器中的创建方式。
scope历史及分类
目前,scope的取值有5种取值:
在Spring 2.0之前,有singleton和prototype两种;
在Spring 2.0之后,为支持web应用的ApplicationContext,增强另外三种:request,session和global session类型,它们只实用于 web程序,通常是和XmlWebApplicationContext共同使用。
单个scope详解

  1. singleton (单一实例)
    此取值时表明容器中创建时只存在一个实例,所有引用此bean都是单一实例。如同每个国家都有一个总统,国家的所有人共用此总统,而这个国家就是一个spring容器,总统就是spring创建的类的bean,国家中的人就是其它调用者,总统是一个表明其在spring中的scope为singleton,也就是单例模型。
    此外,singleton类型的bean定义从容器启动到第一次被请求而实例化开始,只要容器不销毁或退出,该类型的bean的单一实例就会一直存活,典型单例模式,如同servlet在web容器中的生命周期。
    2)prototype
    spring容器在进行输出 prototype的bean 对象时,会每次都重新生成一个新的对象给请求方,虽然这种类型的对象的实例化以及属性设置等工作都是由容器负责的,但是只要准备完毕,并且对象实例返回给请求方之后,容器就不在拥有当前对象的引用,请求方需要自己负责当前对象后继生命周期的管理工作,包括该对象的销毁。也就是说,容器每次返回请求方该对象的一个新的实例之后,就由这个对象“自生自灭”,最典型的体现就是spring与struts2进行整合时,要把action的scope改为prototype。
    如同分苹果,将苹果的bean的scope属性声明为prototype,在每个人领取苹果的时候,我们都是发一个新的苹果给他,发完之后,别人爱怎么吃就怎么吃,爱什么时候吃什么时候吃,但是注意吃完要把苹果核扔到垃圾箱!对于那些不能共享使用的对象类型,应该将其定义的scope设为prototype。
    3)request
    再次说明 request,session和global session类型只实用于 web程序,通常是和XmlWebApplicationContext共同使用。
<bean id ="requestPrecessor" class="...RequestPrecessor"   scope="request" />

Spring容器,即XmlWebApplicationContext 会为每个HTTP请求创建一个全新的RequestPrecessor对象,当请求结束后,该对象的生命周期即告结束, **如同java web中request的生命周期 **。 当同时有100个HTTP请求进来的时候,容器会分别针对这10个请求创建10个全新的RequestPrecessor实例,且他们相互之间互不干扰, 简单来讲, request可以看做prototype的一种特例 ,除了场景更加具体之外,语意上差不多。
4)session
对于web应用来说,放到session中最普遍的就是用户的登录信息,对于这种放到session中的信息,我们可以使用如下形式的制定scope为session:

<bean id ="userPreferences" class="...UserPreferences"   scope="session" />

Spring容器会为每个独立的session创建属于自己的全新的UserPreferences实例,比request scope的bean会存活更长的时间,其他的方面没区别, 如果java web中session的生命周期
5)global session

<bean id ="userPreferences" class="...UserPreferences"   scope="globalsession" />

global session只有应用在基于porlet的web应用程序中才有意义,它映射到porlet的global范围的session,如果普通的servlet的web 应用中使用了这个scope,容器会把它作为普通的session的scope对待。

@Scope声明现在就能看懂了吧

@Component
@Scope("request")
public class ContactResource {
...
}

part 2 . Spring MVC Annotations

@Controller, @RequestMapping,@PathVariable,@RequestParam这几个太常用了,来不及解释了,补充一点就是还可以使用 @RequestHeader获得header信息

@ModelAttribute是java中的数据绑定,用于将表单对应项绑定到模型

@Controller
@RequestMapping("/company")
public class CompanyController {
 
  @Autowired
  private CompanyService companyService;
 
  @RequestMapping("/add")
  public String saveNewCompany(@ModelAttribute Company company) {
    companyService.add(company);
    return "redirect:" + company.getName();
  }
...
}

@SessionAttributes就是保存session,定义在一个Controller类上

@RestController
@RequestMapping("/user")
@SessionAttributes("currUser")
public class UserController {
    @Autowired
    private UserRepo userRepo;
    @Transactional
    @RequestMapping("/save")
    public User save(User user){
       User newUser =  userRepo.save(user);
       return  newUser;
    }
}

SessionAttributes 可以和ModelAttribute结合使用, 我们可以在需要访问 Session 属性的 controller 上加上 @SessionAttributes,然后在 action 需要的 User 参数上加上 @ModelAttribute,并保证两者的属性名称一致。

@Controller  
@SessionAttributes("currentUser")   
public class GreetingController{  
@RequestMapping  
public void hello (@ModelAttribute("currentUser")  User user){  
  //user.sayHello()  
}  
} 

一个综合以上的实例:

@Controller
@RequestMapping("/owners/{ownerId}/pets/{petId}/edit")
@SessionAttributes("pet")
public class EditPetForm {
 
    @ModelAttribute("types")
     
    public Collection<PetType> populatePetTypes() {
        return this.clinic.getPetTypes();
    }
     
    @RequestMapping(method = RequestMethod.POST)
    public String processSubmit(@ModelAttribute("pet") Pet pet, 
            BindingResult result, SessionStatus status) {
        new PetValidator().validate(pet, result);
        if (result.hasErrors()) {
            return "petForm";
        }else {
            this.clinic.storePet(pet);
            status.setComplete();
            return "redirect:owner.do?ownerId="
                + pet.getOwner().getId();
        }
    }
}

@PreAuthorize:预检查

@Transactional
@PreAuthorize("hasRole('ROLE_ADMIN')")
public void removeContact(Integer id) {
  contactDAO.removeContact(id);
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容